[
  {
    "path": "00_Introduction/Readme.md",
    "content": "# Part 0: Introduction\n\nI've decided to go on a compiler writing journey. In the past I've written some\n[assemblers](https://github.com/DoctorWkt/pdp7-unix/blob/master/tools/as7), and\nI've written a [simple compiler](https://github.com/DoctorWkt/h-compiler)\nfor a typeless language. But I've never written a compiler that can compile\nitself. So that's where I'm headed on this journey.\n\nAs part of the process, I'm going to write up my work so that others can\nfollow along. This will also help me to clarify my thoughts and ideas.\nHopefully you, and I, will find this useful!\n\n## Goals of the Journey\n\nHere are my goals, and non-goals, for the journey:\n\n + To write a self-compiling compiler. I think that if the compiler can\n   compile itself, it gets to call itself a *real* compiler.\n + To target at least one real hardware platform. I've seen a few compilers\n   that generate code for hypothetical machines. I want my compiler to\n   work on real hardware. Also, if possible, I want to write the compiler\n   so that it can support multiple backends for different hardware platforms.\n + Practical before research. There's a whole lot of research in the area of\n   compilers. I want to start from absolute zero on this journey, so I'll\n   tend to go for a practical approach and not a theory-heavy approach. That\n   said, there will be times when I'll need to introduce (and implement) some\n   theory-based stuff.\n + Follow the KISS principle: keep it simple, stupid! I'm definitely going to\n   be using Ken Thompson's principle here: \"When in doubt, use brute force.\"\n + Take a lot of small steps to reach the final goal. I'll break the journey\n   up into a lot of simple steps instead of taking large leaps. This will\n   make each new addition to the compiler a bite-sized and easily digestible\n   thing.\n\n## Target Language\n\nThe choice of a target language is difficult. If I choose a high-level\nlanguage like Python, Go etc., then I'll have to implement a whole pile\nof libraries and classes as they are built-in to the language.\n\nI could write a compiler for a language like Lisp, but these can be\n[done easily](ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-039.pdf).\n\nInstead, I've fallen back on the old standby and I'm going to write a\ncompiler for a subset of C, enough to allow the compiler to compile\nitself.\n\nC is just a step up from assembly language (for some subset of C, not\n[C18](https://en.wikipedia.org/wiki/C18_(C_standard_revision))), and this\nwill help make the task of compiling the C code down to assembly somewhat\neasier. Oh, and I also like C.\n\n## The Basics of a Compiler's Job\n\nThe job of a compiler is to translate input in one language (usually\na high-level language) into a different output language (usually a\nlower-level language than the input). The main steps are:\n\n![](Figs/parsing_steps.png)\n\n + Do [lexical analysis](https://en.wikipedia.org/wiki/Lexical_analysis)\nto recognise the lexical elements. In several languages, `=` is different\nto `==`, so you can't just read a single `=`. We call these lexical\nelements *tokens*.\n + [Parse](https://en.wikipedia.org/wiki/Parsing) the input, i.e. recognise\nthe syntax and structural elements of the input and ensure that they\nconform to the *grammar* of the language. For example, your language\nmight have this decision-making\nstructure:\n\n```\n      if (x < 23) {\n        print(\"x is smaller than 23\\n\");\n      }\n```\n\n> but in another language you might write:\n\n```\n      if (x < 23):\n        print(\"x is smaller than 23\\n\")\n```\n\n> This is also the place where the compiler can detect syntax errors, like if\nthe semicolon was missing on the end of the first *print* statement.\n\n + Do [semantic analysis](https://en.wikipedia.org/wiki/Semantic_analysis_(compilers))\n   of the input, i.e. understand the meaning of the input. This is actually different\n   from recognising the syntax and structure. For example, in English, a\n   sentence might have the form `<subject> <verb> <adjective> <object>`.\n   The following two sentences have the same structure, but completely\n   different meaning:\n\n```\n          David ate lovely bananas.\n          Jennifer hates green tomatoes.\n```\n\n + [Translate](https://en.wikipedia.org/wiki/Code_generation_(compiler))\n   the meaning of the input into a different language. Here we\n   convert the input, parts at a time, into a lower-level language.\n  \n## Resources\n\nThere's a lot of compiler resources out on the Internet. Here are the ones\nI'll be looking at.\n\n### Learning Resources\n\nIf you want to start with some books, papers and tools on compilers,\nI'd highly recommend this list:\n\n  + [Curated list of awesome resources on Compilers, Interpreters and Runtimes](https://github.com/aalhour/awesome-compilers) by Ahmad Alhour\n\n### Existing Compilers\n\nWhile I'm going to build my own compiler, I plan on looking at other compilers\nfor ideas and probably also borrow some of their code. Here are the ones\nI'm looking at:\n\n  + [SubC](http://www.t3x.org/subc/) by Nils M Holm\n  + [Swieros C Compiler](https://github.com/rswier/swieros/blob/master/root/bin/c.c) by Robert Swierczek\n  + [fbcc](https://github.com/DoctorWkt/fbcc) by Fabrice Bellard\n  + [tcc](https://bellard.org/tcc/), also by Fabrice Bellard and others\n  + [catc](https://github.com/yui0/catc) by Yuichiro Nakada\n  + [amacc](https://github.com/jserv/amacc) by Jim Huang\n  + [Small C](https://en.wikipedia.org/wiki/Small-C) by Ron Cain,\n    James E. Hendrix, derivatives by others\n\nIn particular, I'll be using a lot of the ideas, and some of the code,\nfrom the SubC compiler.\n\n## Setting Up the Development Environment\n\nAssuming that you want to come along on this journey, here's what you'll\nneed. I'm going to use a Linux development environment, so download and\nset up your favourite Linux system: I'm using Lubuntu 18.04.\n\nI'm going to target two hardware platforms: Intel x86-64 and 32-bit ARM.\nI'll use a PC running Lubuntu 18.04 as the Intel target, and a Raspberry\nPi running Raspbian as the ARM target.\n\nOn the Intel platform, we are going to need an existing C compiler.\nSo, install this package (I give the Ubuntu/Debian commands):\n\n```\n  $ sudo apt-get install build-essential\n```\n\nIf there are any more tools required for a vanilla Linux\nsystem, let me know.\n\nFinally, clone a copy of this Github repository.\n\n## The Next Step\n\nIn the next part of our compiler writing journey, we will start with\nthe code to scan our input file and find the *tokens* that are the\nlexical elements of our language. [Next step](../01_Scanner/Readme.md)\n"
  },
  {
    "path": "01_Scanner/Makefile",
    "content": "scanner: main.c scan.c\n\tcc -o scanner -g main.c scan.c\n\nclean:\n\trm -f scanner *.o\n"
  },
  {
    "path": "01_Scanner/Readme.md",
    "content": "# Part 1: Introduction to Lexical Scanning\n\nWe start our compiler writing journey with a simple lexical scanner.\nAs I mentioned in the previous part, the job of the scanner\nis to identify the lexical elements, or *tokens*, in the input language.\n\nWe will start with a language that has only five lexical elements:\n\n + the four basic maths operators: `*`, `/`, `+` and `-`\n + decimal whole numbers which have 1 or more digits `0` .. `9`\n\nEach token that we scan is going to be stored in this structure\n(from `defs.h`):\n\n```c\n// Token structure\nstruct token {\n  int token;\n  int intvalue;\n};\n```\n\nwhere the `token` field can be one of these values (from `defs.h`):\n\n```c\n// Tokens\nenum {\n  T_PLUS, T_MINUS, T_STAR, T_SLASH, T_INTLIT\n};\n```\n\nWhen the token is a `T_INTLIT` (i.e. an integer literal), the `intvalue`\nfield will hold the value of the integer that we scanned in.\n\n## Functions in `scan.c`\n\nThe `scan.c` file holds the functions of our lexical scanner. We are going\nto read in one character at a time from our input file. However, there will\nbe times when we need to \"put back\" a character if we have read too far\nahead in the input stream. We also want to track what line we are currently\non so that we can print the line number in our debug messages. All of this\nis done by the `next()` function:\n\n```c\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {                // Use the character put\n    c = Putback;                // back if there is one\n    Putback = 0;\n    return c;\n  }\n\n  c = fgetc(Infile);            // Read from input file\n  if ('\\n' == c)\n    Line++;                     // Increment line count\n  return c;\n}\n```\n\nThe `Putback` and `Line` variables are defined in `data.h` along with\nour input file pointer:\n\n```c\nextern_ int     Line;\nextern_ int     Putback;\nextern_ FILE    *Infile;\n```\n\nAll C files will include this where `extern_` is replaced with `extern`.\nBut `main.c` will remove the `extern_`; hence, these variables will\n\"belong\" to `main.c`.\n\nFinally, how do we put a character back into the input stream? Thus:\n\n```c\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n```\n\n## Ignoring Whitespace\n\nWe need a function that reads and silently skips whitespace characters\nuntil it gets a non-whitespace character, and returns it. Thus:\n\n```c\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n```\n\n## Scanning Tokens: `scan()`\n\nSo now we can read characters in while skipping whitespace; we can also\nput back a character if we read one character too far ahead. We can\nnow write our first lexical scanner:\n\n```c\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c;\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n  case EOF:\n    return (0);\n  case '+':\n    t->token = T_PLUS;\n    break;\n  case '-':\n    t->token = T_MINUS;\n    break;\n  case '*':\n    t->token = T_STAR;\n    break;\n  case '/':\n    t->token = T_SLASH;\n    break;\n  default:\n    // More here soon\n  }\n\n  // We found a token\n  return (1);\n}\n```\n\nThat's it for the simple one-character tokens: for each recognised\ncharacter, turn it into a token. You may ask: why not just put\nthe recognised character into the `struct token`? The answer is that later\nwe will need to recognise multi-character tokens such as `==` and keywords\nlike `if` and `while`. So it will make life easier to have an enumerated\nlist of token values.\n\n## Integer Literal Values\n\nIn fact, we already have to face this situation as we also need to\nrecognise integer literal values like `3827` and `87731`. Here is the\nmissing `default` code from the `switch` statement:\n\n```c\n  default:\n\n    // If it's a digit, scan the\n    // literal integer value in\n    if (isdigit(c)) {\n      t->intvalue = scanint(c);\n      t->token = T_INTLIT;\n      break;\n    }\n\n    printf(\"Unrecognised character %c on line %d\\n\", c, Line);\n    exit(1);\n```\n\nOnce we hit a decimal digit character, we call the helper function `scanint()`\nwith this first character. It will return the scanned integer value. To\ndo this, it has to read each character in turn, check that it's a\nlegitimate digit, and build up the final number. Here is the code:\n\n```c\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return val;\n}\n```\n\nWe start with a zero `val` value. Each time we get a character\nin the set `0` to `9` we convert this to an `int` value with\n`chrpos()`. We make `val` 10 times bigger and then add this new\ndigit to it.\n\nFor example, if we have the characters `3`, `2`, `8`, we do:\n\n + `val= 0 * 10 + 3`, i.e. 3\n + `val= 3 * 10 + 2`, i.e. 32\n + `val= 32 * 10 + 8`, i.e. 328\n\nRight at the end, did you notice the call to `putback(c)`?\nWe found a character that's not a decimal digit at this point.\nWe can't simply discard it, but luckily we can put it back\nin the input stream to be consumed later.\n\nYou may also ask at this point: why not simply subtract the ASCII value of \n'0' from `c` to make it an integer? The answer is that, later on, we will\nbe able to do `chrpos(\"0123456789abcdef\")` to convert hexadecimal digits\nas well.\n\nHere's the code for `chrpos()`:\n\n```c\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n```\n\nAnd that's it for the lexical scanner code in `scan.c` for now.\n\n## Putting the Scanner to Work\n\nThe code in `main.c` puts the above scanner to work. The `main()`\nfunction opens up a file and then scans it for tokens:\n\n```c\nvoid main(int argc, char *argv[]) {\n  ...\n  init();\n  ...\n  Infile = fopen(argv[1], \"r\");\n  ...\n  scanfile();\n  exit(0);\n}\n```\n\nAnd `scanfile()` loops while there is a new token and prints out the\ndetails of the token:\n\n```c\n// List of printable tokens\nchar *tokstr[] = { \"+\", \"-\", \"*\", \"/\", \"intlit\" };\n\n// Loop scanning in all the tokens in the input file.\n// Print out details of each token found.\nstatic void scanfile() {\n  struct token T;\n\n  while (scan(&T)) {\n    printf(\"Token %s\", tokstr[T.token]);\n    if (T.token == T_INTLIT)\n      printf(\", value %d\", T.intvalue);\n    printf(\"\\n\");\n  }\n}\n```\n\n## Some Example Input Files\n\nI've provided some example input files so you can see what tokens\nthe scanner finds in each file, and what input files the scanner rejects.\n\n```\n$ make\ncc -o scanner -g main.c scan.c\n\n$ cat input01\n2 + 3 * 5 - 8 / 3\n\n$ ./scanner input01\nToken intlit, value 2\nToken +\nToken intlit, value 3\nToken *\nToken intlit, value 5\nToken -\nToken intlit, value 8\nToken /\nToken intlit, value 3\n\n$ cat input04\n23 +\n18 -\n45.6 * 2\n/ 18\n\n$ ./scanner input04\nToken intlit, value 23\nToken +\nToken intlit, value 18\nToken -\nToken intlit, value 45\nUnrecognised character . on line 3\n```\n\n## Conclusion and What's Next\n\nWe've started small and we have a simple lexical scanner that recognises\nthe four main maths operators and also integer literal values. We saw\nthat we needed to skip whitespace and put back characters if we read\ntoo far into the input.\n\nSingle character tokens are easy to scan, but multi-character tokens are\na bit harder. But at the end, the `scan()` function returns the next token\nfrom the input file in a `struct token` variable:\n\n```c\nstruct token {\n  int token;\n  int intvalue;\n};\n```\n\nIn the next part of our compiler writing journey, we will build\na recursive descent parser to interpret the grammar of our input\nfiles, and calculate & print out the final value for each file. [Next step](../02_Parser/Readme.md)\n"
  },
  {
    "path": "01_Scanner/data.h",
    "content": "#ifndef extern_\n #define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int     Line;\nextern_ int\tPutback;\nextern_ FILE\t*Infile;\n"
  },
  {
    "path": "01_Scanner/decl.h",
    "content": "\n// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\nint scan(struct token *t);\n"
  },
  {
    "path": "01_Scanner/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Tokens\nenum {\n  T_PLUS, T_MINUS, T_STAR, T_SLASH, T_INTLIT\n};\n\n// Token structure\nstruct token {\n  int token;\n  int intvalue;\n};\n"
  },
  {
    "path": "01_Scanner/input01",
    "content": "2 + 3 * 5 - 8 / 3\n"
  },
  {
    "path": "01_Scanner/input02",
    "content": "13 -6+  4*\n5\n       +\n08 / 3\n"
  },
  {
    "path": "01_Scanner/input03",
    "content": "12 34 + -56 * / - - 8 + * 2\n"
  },
  {
    "path": "01_Scanner/input04",
    "content": "23 +\n18 -\n45.6 * 2\n/ 18\n"
  },
  {
    "path": "01_Scanner/input05",
    "content": "23 * 456abcdefg\n"
  },
  {
    "path": "01_Scanner/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// List of printable tokens\nchar *tokstr[] = { \"+\", \"-\", \"*\", \"/\", \"intlit\" };\n\n// Loop scanning in all the tokens in the input file.\n// Print out details of each token found.\nstatic void scanfile() {\n  struct token T;\n\n  while (scan(&T)) {\n    printf(\"Token %s\", tokstr[T.token]);\n    if (T.token == T_INTLIT)\n      printf(\", value %d\", T.intvalue);\n    printf(\"\\n\");\n  }\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nvoid main(int argc, char *argv[]) {\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n\n  scanfile();\n  exit(0);\n}\n"
  },
  {
    "path": "01_Scanner/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return c;\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return c;\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return val;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c;\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n  case EOF:\n    return (0);\n  case '+':\n    t->token = T_PLUS;\n    break;\n  case '-':\n    t->token = T_MINUS;\n    break;\n  case '*':\n    t->token = T_STAR;\n    break;\n  case '/':\n    t->token = T_SLASH;\n    break;\n  default:\n\n    // If it's a digit, scan the\n    // literal integer value in\n    if (isdigit(c)) {\n      t->intvalue = scanint(c);\n      t->token = T_INTLIT;\n      break;\n    }\n\n    printf(\"Unrecognised character %c on line %d\\n\", c, Line);\n    exit(1);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "02_Parser/Makefile",
    "content": "parser: expr.c interp.c main.c scan.c tree.c\n\tcc -o parser -g expr.c interp.c main.c scan.c tree.c\n\nclean:\n\trm -f parser *.o\n"
  },
  {
    "path": "02_Parser/Readme.md",
    "content": "# Part 2: Introduction to Parsing\n\nIn this part of our compiler writing journey, I'm going to introduce the\nbasics of a parser. As I mentioned in the first part, the job of the parser\nis to recognise the syntax and structural elements of the input and ensure\nthat they conform to the *grammar* of the language.\n\nWe already have several language elements that we can scan in, i.e. our tokens:\n\n + the four basic maths operators: `*`, `/`, `+` and `-`\n + decimal whole numbers which have 1 or more digits `0` .. `9`\n\nNow let's define a grammar for the language that our parser will recognise.\n\n## BNF: Backus-Naur Form\n\nYou will come across the use of\n[BNF ](https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form)\nat some point if you get into dealing\nwith computer languages. I will just introduce enough of the BNF syntax\nhere to express the grammar we want to recognise.\n\nWe want a grammar to express maths expressions with whole numbers. Here is\nthe BNF description of the grammar:\n\n```\nexpression: number\n          | expression '*' expression\n          | expression '/' expression\n          | expression '+' expression\n          | expression '-' expression\n          ;\n\nnumber:  T_INTLIT\n         ;\n```\n\nThe vertical bars separate options in the grammar, so the above says:\n\n  + An expression could be just a number, or\n  + An expression is two expressions separated by a '*' token, or\n  + An expression is two expressions separated by a '/' token, or\n  + An expression is two expressions separated by a '+' token, or\n  + An expression is two expressions separated by a '-' token\n  + A number is always a T_INTLIT token\n\nIt should be pretty obvious that the BNF definition of the grammar is\n*recursive*: an expression is defined by referencing other expressions.\nBut there is a way to *bottom-out\" the recursion: when an expression\nturns out to be a number, this is always a T_INTLIT token and thus\nnot recursive.\n\nIn BNF, we say that \"expression\" and \"number\" are *non-terminal* symbols, as\nthey are produced by rules in the grammar. However, T_INTLIT is a *terminal*\nsymbol as it is not defined by any rule. Instead, it is an already-recognised\ntoken in the language. Similarly, the four maths operator tokens are\nterminal symbols.\n \n## Recursive Descent Parsing\n\nGiven that the grammar for our language is recursive, it makes sense for\nus to try and parse it recursively. What we need to do is to read in a\ntoken, then *look ahead* to the next token. Based on what the next token\nis, we can then decide what path we need to take to parse the input.\nThis may require us to recursively call a function that has already been\ncalled.\n\nIn our case, the first token in any expression will be a number and this\nmay be followed by maths operator. After that there may only\nbe a single number, or there may be the start of a whole new expression.\nHow can we parse this recursively?\n\nWe can write pseudo-code that looks like this:\n\n```\nfunction expression() {\n  Scan and check the first token is a number. Error if it's not\n  Get the next token\n  If we have reached the end of the input, return, i.e. base case\n\n  Otherwise, call expression()\n}\n```\n\nLet's run this function on the input `2 + 3 - 5 T_EOF` where `T_EOF`\nis a token that reflects the end of the input. I will number each\ncall to `expression()`.\n\n```\nexpression0:\n  Scan in the 2, it's a number\n  Get next token, +, which isn't T_EOF\n  Call expression()\n\n    expression1:\n      Scan in the 3, it's a number\n      Get next token, -, which isn't T_EOF\n      Call expression()\n\n        expression2:\n          Scan in the 5, it's a number\n          Get next token, T_EOF, so return from expression2\n\n      return from expression1\n  return from expression0\n```\n\nYes, the function was able to recursively parse the input\n`2 + 3 - 5 T_EOF`.\n\nOf course, we haven't done anything with the\ninput, but that isn't the job of the parser. The parser's job is\nto *recognise* the input, and warn of any syntax errors. Someone\nelse is going to do the *semantic analysis* of the input, i.e. to\nunderstand and perform the meaning of this input.\n\n> Later on, you will see that this isn't actually true. It often makes\n  sense to intertwine the syntax analysis and semantic analysis.\n\n## Abstract Syntax Trees\n\nTo do the semantic analysis, we need code that either interprets\nthe recognised input, or translates it to another format, e.g.\nassembly code. In this part of the journey, we will build an\ninterpreter for the input. But to get there, we are first going to\nconvert the input into an\n[abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree),\nalso known as an AST.\n\nI highly recommend you read this short explanation of ASTs:\n\n + [Leveling Up One’s Parsing Game With ASTs](https://medium.com/basecs/leveling-up-ones-parsing-game-with-asts-d7a6fc2400ff)\n   by Vaidehi Joshi\n\nIt's well written and really help to explain the purpose and structure of ASTs.\nDon't worry, I'll be here when you get back.\n\nThe structure of each node in the AST that we will build is described in\n`defs.h`:\n\n```c\n// AST node types\nenum {\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_INTLIT\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                               // \"Operation\" to be performed on this tree\n  struct ASTnode *left;                 // Left and right child trees\n  struct ASTnode *right;\n  int intvalue;                         // For A_INTLIT, the integer value\n};\n```\n\nSome AST nodes, like those with `op` values `A_ADD` and `A_SUBTRACT`\nhave two child ASTs that are pointed to by `left` and `right`. Later on,\nwe will add or subtract the values of the sub-trees.\n\nAlternatively, an AST node with the `op` value A_INTLIT represents\nan integer value. It has no sub-tree children, just a value in the\n`intvalue` field.\n\n## Building AST Nodes and Trees\n\nThe code in `tree.c` has the functions to build ASTs. The most\ngeneral function, `mkastnode()`, takes values for all four\nfields in an AST node. It allocates the node, populates the field\nvalues and returns a pointer to the node:\n\n```c\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n                          struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL) {\n    fprintf(stderr, \"Unable to malloc in mkastnode()\\n\");\n    exit(1);\n  }\n  // Copy in the field values and return it\n  n->op = op;\n  n->left = left;\n  n->right = right;\n  n->intvalue = intvalue;\n  return (n);\n}\n```\n\nGiven this, we can write more specific functions that make a leaf AST\nnode (i.e. one with no children), and make an AST node with a single child:\n\n```c\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int intvalue) {\n  return (mkastnode(op, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue) {\n  return (mkastnode(op, left, NULL, intvalue));\n```\n\n## Purpose of the AST\n\nWe are going to use an AST to store each expression that we recognise\nso that, later on, we can traverse it recursively to calculate the\nfinal value of the expression. We do want to deal with the precedence of the \nmaths operators. Here is an example.\n\nConsider the expression `2 * 3 + 4 * 5`. Now, multiplication has higher\nprecedence that addition. Therefore, we want to *bind* the multiplication\noperands together and perform these operations before we do the addition.\n\nIf we generated the AST tree to look like this:\n\n```\n          +\n         / \\\n        /   \\\n       /     \\\n      *       *\n     / \\     / \\\n    2   3   4   5\n```\n\nthen, when traversing the tree, we would perform `2*3` first, then `4*5`.\nOnce we have these results, we can then pass them up to the root of the\ntree to perform the addition.\n\n## A Naive Expression Parser\n\nNow, we could re-use the token values from our scanner as the AST node\noperation values, but I like to keep the concept of tokens and AST nodes\nseparate. So, to start with, I'm going to have a function to map\nthe token values into AST node operation values. This, along with the\nrest of the parser, is in `expr.c`:\n\n```c\n// Convert a token into an AST operation.\nint arithop(int tok) {\n  switch (tok) {\n    case T_PLUS:\n      return (A_ADD);\n    case T_MINUS:\n      return (A_SUBTRACT);\n    case T_STAR:\n      return (A_MULTIPLY);\n    case T_SLASH:\n      return (A_DIVIDE);\n    default:\n      fprintf(stderr, \"unknown token in arithop() on line %d\\n\", Line);\n      exit(1);\n  }\n}\n```\n\nThe default statement in the switch statement fires when we can't convert\nthe given token into an AST node type. It's going to form part of the\nsyntax checking in our parser.\n\nWe need a function to check that the next token is an integer literal,\nand to build an AST node to hold the literal value. Here it is:\n\n```c\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n\n  // For an INTLIT token, make a leaf AST node for it\n  // and scan in the next token. Otherwise, a syntax error\n  // for any other token type.\n  switch (Token.token) {\n    case T_INTLIT:\n      n = mkastleaf(A_INTLIT, Token.intvalue);\n      scan(&Token);\n      return (n);\n    default:\n      fprintf(stderr, \"syntax error on line %d\\n\", Line);\n      exit(1);\n  }\n}\n```\n\nThis assumes that there is a global variable `Token`, and that it\nalready has the most recent token scanned in from the input. In\n`data.h`:\n\n```c\nextern_ struct token    Token;\n```\n\nand in `main()`:\n\n```c\n  scan(&Token);                 // Get the first token from the input\n  n = binexpr();                // Parse the expression in the file\n```\n\nNow we can write the code for the parser:\n\n```c\n// Return an AST tree whose root is a binary operator\nstruct ASTnode *binexpr(void) {\n  struct ASTnode *n, *left, *right;\n  int nodetype;\n\n  // Get the integer literal on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If no tokens left, return just the left node\n  if (Token.token == T_EOF)\n    return (left);\n\n  // Convert the token into a node type\n  nodetype = arithop(Token.token);\n\n  // Get the next token in\n  scan(&Token);\n\n  // Recursively get the right-hand tree\n  right = binexpr();\n\n  // Now build a tree with both sub-trees\n  n = mkastnode(nodetype, left, right, 0);\n  return (n);\n}\n```\n\nNotice that nowhere in this naive parser code is there anything to\ndeal with different operator precedence. As it stands, the code treats\nall operators as having equal precedence. If you follow the code as\nit parses the expression `2 * 3 + 4 * 5`, you will see that it\nbuilds this AST:\n\n```\n     *\n    / \\\n   2   +\n      / \\\n     3   *\n        / \\\n       4   5\n```\n\nThis is definitely not correct. It will multiply `4*5` to get 20,\nthen do `3+20` to get 23 instead of doing `2*3` to get 6.\n\nSo why did I do this? I wanted to show you that writing a simple parser\nis easy, but getting it to also do the semantic analysis is harder.\n\n## Interpreting the Tree\n\nNow that we have our (incorrect) AST tree, let's write some code to\ninterpret it. Again, we are going to write recursive code to traverse\nthe tree. Here's the pseudo-code:\n\n```\ninterpretTree:\n  First, interpret the left-hand sub-tree and get its value\n  Then, interpret the right-hand sub-tree and get its value\n  Perform the operation in the node at the root of our tree\n  on the two sub-tree values, and return this value\n```\n\nGoing back to the correct AST tree:\n\n```\n          +\n         / \\\n        /   \\\n       /     \\\n      *       *\n     / \\     / \\\n    2   3   4   5\n```\n\nthe call structure would look like:\n\n```\ninterpretTree0(tree with +):\n  Call interpretTree1(left tree with *):\n     Call interpretTree2(tree with 2):\n       No maths operation, just return 2\n     Call interpretTree3(tree with 3):\n       No maths operation, just return 3\n     Perform 2 * 3, return 6\n\n  Call interpretTree1(right tree with *):\n     Call interpretTree2(tree with 4):\n       No maths operation, just return 4\n     Call interpretTree3(tree with 5):\n       No maths operation, just return 5\n     Perform 4 * 5, return 20\n\n  Perform 6 + 20, return 26\n```\n\n## Code to Interpret the Tree\n\nThis is in `interp.c` and follows the above pseudo-code:\n\n```c\n// Given an AST, interpret the\n// operators in it and return\n// a final value.\nint interpretAST(struct ASTnode *n) {\n  int leftval, rightval;\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftval = interpretAST(n->left);\n  if (n->right)\n    rightval = interpretAST(n->right);\n\n  switch (n->op) {\n    case A_ADD:\n      return (leftval + rightval);\n    case A_SUBTRACT:\n      return (leftval - rightval);\n    case A_MULTIPLY:\n      return (leftval * rightval);\n    case A_DIVIDE:\n      return (leftval / rightval);\n    case A_INTLIT:\n      return (n->intvalue);\n    default:\n      fprintf(stderr, \"Unknown AST operator %d\\n\", n->op);\n      exit(1);\n  }\n}\n```\n   \nAgain, the default statement in the switch statement fires when we can't \ninterpret the AST node type. It's going to form part of the\nsematic checking in our parser.\n\n## Building the Parser\n\nThere is some other code here and the, like the call to the interpreter\nin `main()`:\n\n```c\n  scan(&Token);                 // Get the first token from the input\n  n = binexpr();                // Parse the expression in the file\n  printf(\"%d\\n\", interpretAST(n));      // Calculate the final result\n  exit(0);\n```\n\nYou can now build the parser by doing:\n\n```\n$ make\ncc -o parser -g expr.c interp.c main.c scan.c tree.c\n```\n\nI've provided several input files for you to test the parser on, but \nof course you can create your own. Remember, the calculated results\nare incorrect, but the parser should detect input errors like\nconsecutive numbers, consecutive operators, and a number missing at the end\nof the input. I've also added some debugging code to the interpreter so\nyou can see which AST tree nodes get evaluated in which order:\n\n```\n$ cat input01\n2 + 3 * 5 - 8 / 3\n\n$ ./parser input01\nint 2\nint 3\nint 5\nint 8\nint 3\n8 / 3\n5 - 2\n3 * 3\n2 + 9\n11\n\n$ cat input02\n13 -6+  4*\n5\n       +\n08 / 3\n\n$ ./parser input02\nint 13\nint 6\nint 4\nint 5\nint 8\nint 3\n8 / 3\n5 + 2\n4 * 7\n6 + 28\n13 - 34\n-21\n\n$ cat input03\n12 34 + -56 * / - - 8 + * 2\n\n$ ./parser input03\nunknown token in arithop() on line 1\n\n$ cat input04\n23 +\n18 -\n45.6 * 2\n/ 18\n\n$ ./parser input04\nUnrecognised character . on line 3\n\n$ cat input05\n23 * 456abcdefg\n\n$ ./parser input05\nUnrecognised character a on line 1\n```\n\n## Conclusion and What's Next\n\nA parser recognises the grammar of the language and checks that the\ninput to the compiler conforms to this grammar. If it doesn't, the parser\nshould print out an error message. As our expression grammar is\nrecursive, we have chosen to write a recursive descent parser to\nrecognise our expressions.\n\nRight now the parser works, as shown by the above output, but it fails\nto get the semantics of the input right. In other words, it doesn't\ncalculate the correct value of the expressions.\n\nIn the next part of our compiler writing journey, we will modify\nthe parser so that it also does the semantic analysis of the\nexpressions to get the right maths results. [Next step](../03_Precedence/Readme.md)\n"
  },
  {
    "path": "02_Parser/data.h",
    "content": "#ifndef extern_\n #define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int     \tLine;\nextern_ int\t\tPutback;\nextern_ FILE\t\t*Infile;\nextern_ struct token\tToken;\n"
  },
  {
    "path": "02_Parser/decl.h",
    "content": "\n// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\nint scan(struct token *t);\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int intvalue);\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue);\nstruct ASTnode *binexpr(void);\nint interpretAST(struct ASTnode *n);\n"
  },
  {
    "path": "02_Parser/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Token types\nenum {\n  T_EOF, T_PLUS, T_MINUS, T_STAR, T_SLASH, T_INTLIT\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types\nenum {\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_INTLIT\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t\t// \"Operation\" to be performed on this tree\n  struct ASTnode *left;\t\t\t// Left and right child trees\n  struct ASTnode *right;\n  int intvalue;\t\t\t\t// For A_INTLIT, the integer value\n};\n"
  },
  {
    "path": "02_Parser/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n\n  // For an INTLIT token, make a leaf AST node for it\n  // and scan in the next token. Otherwise, a syntax error\n  // for any other token type.\n  switch (Token.token) {\n    case T_INTLIT:\n      n = mkastleaf(A_INTLIT, Token.intvalue);\n      scan(&Token);\n      return (n);\n    default:\n      fprintf(stderr, \"syntax error on line %d\\n\", Line);\n      exit(1);\n  }\n}\n\n\n// Convert a token into an AST operation.\nint arithop(int tok) {\n  switch (tok) {\n    case T_PLUS:\n      return (A_ADD);\n    case T_MINUS:\n      return (A_SUBTRACT);\n    case T_STAR:\n      return (A_MULTIPLY);\n    case T_SLASH:\n      return (A_DIVIDE);\n    default:\n      fprintf(stderr, \"unknown token in arithop() on line %d\\n\", Line);\n      exit(1);\n  }\n}\n\n\n// Return an AST tree whose root is a binary operator\nstruct ASTnode *binexpr(void) {\n  struct ASTnode *n, *left, *right;\n  int nodetype;\n\n  // Get the integer literal on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If no tokens left, return just the left node\n  if (Token.token == T_EOF)\n    return (left);\n\n  // Convert the token into a node type\n  nodetype = arithop(Token.token);\n\n  // Get the next token in\n  scan(&Token);\n\n  // Recursively get the right-hand tree\n  right = binexpr();\n\n  // Now build a tree with both sub-trees\n  n = mkastnode(nodetype, left, right, 0);\n  return (n);\n}\n"
  },
  {
    "path": "02_Parser/input01",
    "content": "2 + 3 * 5 - 8 / 3\n"
  },
  {
    "path": "02_Parser/input02",
    "content": "13 -6+  4*\n5\n       +\n08 / 3\n"
  },
  {
    "path": "02_Parser/input03",
    "content": "12 34 + -56 * / - - 8 + * 2\n"
  },
  {
    "path": "02_Parser/input04",
    "content": "23 +\n18 -\n45.6 * 2\n/ 18\n"
  },
  {
    "path": "02_Parser/input05",
    "content": "23 * 456abcdefg\n"
  },
  {
    "path": "02_Parser/interp.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree interpreter\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// List of AST operators\nstatic char *ASTop[] = { \"+\", \"-\", \"*\", \"/\" };\n\n// Given an AST, interpret the\n// operators in it and return\n// a final value.\nint interpretAST(struct ASTnode *n) {\n  int leftval, rightval;\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftval = interpretAST(n->left);\n  if (n->right)\n    rightval = interpretAST(n->right);\n\n  // Debug: Print what we are about to do\n  if (n->op == A_INTLIT)\n    printf(\"int %d\\n\", n->intvalue);\n  else\n    printf(\"%d %s %d\\n\", leftval, ASTop[n->op], rightval);\n\n  switch (n->op) {\n    case A_ADD:\n      return (leftval + rightval);\n    case A_SUBTRACT:\n      return (leftval - rightval);\n    case A_MULTIPLY:\n      return (leftval * rightval);\n    case A_DIVIDE:\n      return (leftval / rightval);\n    case A_INTLIT:\n      return (n->intvalue);\n    default:\n      fprintf(stderr, \"Unknown AST operator %d\\n\", n->op);\n      exit(1);\n  }\n}\n"
  },
  {
    "path": "02_Parser/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nvoid main(int argc, char *argv[]) {\n  struct ASTnode *n;\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  n = binexpr();\t\t// Parse the expression in the file\n  printf(\"%d\\n\", interpretAST(n));\t// Calculate the final result\n  exit(0);\n}\n"
  },
  {
    "path": "02_Parser/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return c;\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return c;\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return val;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c;\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n  case EOF:\n    t->token = T_EOF;\n    return (0);\n  case '+':\n    t->token = T_PLUS;\n    break;\n  case '-':\n    t->token = T_MINUS;\n    break;\n  case '*':\n    t->token = T_STAR;\n    break;\n  case '/':\n    t->token = T_SLASH;\n    break;\n  default:\n\n    // If it's a digit, scan the\n    // literal integer value in\n    if (isdigit(c)) {\n      t->intvalue = scanint(c);\n      t->token = T_INTLIT;\n      break;\n    }\n\n    printf(\"Unrecognised character %c on line %d\\n\", c, Line);\n    exit(1);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "02_Parser/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL) {\n    fprintf(stderr, \"Unable to malloc in mkastnode()\\n\");\n    exit(1);\n  }\n  // Copy in the field values and return it\n  n->op = op;\n  n->left = left;\n  n->right = right;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int intvalue) {\n  return (mkastnode(op, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue) {\n  return (mkastnode(op, left, NULL, intvalue));\n}\n"
  },
  {
    "path": "03_Precedence/Makefile",
    "content": "parser: expr.c interp.c main.c scan.c tree.c\n\tcc -o parser -g expr.c interp.c main.c scan.c tree.c\n\nparser2: expr2.c interp.c main.c scan.c tree.c\n\tcc -o parser2 -g expr2.c interp.c main.c scan.c tree.c\nclean:\n\trm -f parser parser2 *.o\n\ntest: parser\n\t-(./parser input01; \\\n\t ./parser input02; \\\n\t ./parser input03; \\\n\t ./parser input04; \\\n\t ./parser input05)\n\ntest2: parser2\n\t-(./parser2 input01; \\\n\t ./parser2 input02; \\\n\t ./parser2 input03; \\\n\t ./parser2 input04; \\\n\t ./parser2 input05)\n"
  },
  {
    "path": "03_Precedence/Readme.md",
    "content": "# Part 3: Operator Precedence\n\nWe saw in the previous part of our compiler writing journey that a parser\ndoesn't necessarily enforce the semantics of our language. It only\nenforces the syntax and structural rules of the grammar.\n\nWe ended up with code that calculates the wrong value of expressions\nlike `2 * 3 + 4 * 5`, because the code created an AST that looks like:\n\n```\n     *\n    / \\\n   2   +\n      / \\\n     3   *\n        / \\\n       4   5\n```\n\ninstead of:\n\n\n```\n          +\n         / \\\n        /   \\\n       /     \\\n      *       *\n     / \\     / \\\n    2   3   4   5\n```\n\nTo solve this, we have to add code to our parser to perform operator\nprecedence. There are (at least) two ways of doing this:\n\n + Making the operator precedence explicit in the language's grammar\n + Influencing the existing parser with an operator precedence table\n\n## Making the Operator Precedence Explicit\n\nHere is our grammar from the last part of the journey:\n\n\n```\nexpression: number\n          | expression '*' expression\n          | expression '/' expression\n          | expression '+' expression\n          | expression '-' expression\n          ;\n\nnumber:  T_INTLIT\n         ;\n```\n\nNote that there is no differentiation between any of the four maths\noperators. Let's tweak the grammar so that there is a difference:\n\n\n```\nexpression: additive_expression\n    ;\n\nadditive_expression:\n      multiplicative_expression\n    | additive_expression '+' multiplicative_expression\n    | additive_expression '-' multiplicative_expression\n    ;\n\nmultiplicative_expression:\n      number\n    | number '*' multiplicative_expression\n    | number '/' multiplicative_expression\n    ;\n\nnumber:  T_INTLIT\n         ;\n```\n\nWe now have two types of expressions: *additive* expressions and\n*multiplicative* expressions. Note that the grammar now forces\nthe numbers to be part of multiplicative expressions only. This\nforces the '*' and '/' operators to bind more tightly to the\nnumbers on either side, thus having higher precedence.\n\nAny additive expression is actually either a multiplicative expression\nby itself, or an additive (i.e. multiplicative) expression followed\nby a '+' or '-' operator then another multiplicative expression.\nThe additive expression is now at a much lower predencence than the\nmultiplicative expression.\n\n## Doing The Above in the Recursive Descent Parser\n\nHow do we take the above version of our grammar and implement it into\nour recursive descent parser? I've done this in the file `expr2.c` and\nI'll cover the code below.\n\nThe answer is to have a `multiplicative_expr()` function to deal with the\n'*' and '/' operators, and an `additive_expr()` function to deal with the\nlower precedence '+' and '-' operators.\n\nBoth functions are going to read in something and an operator.\nThen, while there are following operators at the same precedence,\neach function will parse some more of the input and combine the left\nand right halves with the first operator.\n\nHowever, `additive_expr()` will have to defer to the higher-precedence\n`multiplicative_expr()` function. Here is how this is done.\n\n## `additive_expr()`\n\n```c\n// Return an AST tree whose root is a '+' or '-' binary operator\nstruct ASTnode *additive_expr(void) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the left sub-tree at a higher precedence than us\n  left = multiplicative_expr();\n\n  // If no tokens left, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_EOF)\n    return (left);\n\n  // Loop working on token at our level of precedence\n  while (1) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Get the right sub-tree at a higher precedence than us\n    right = multiplicative_expr();\n\n    // Join the two sub-trees with our low-precedence operator\n    left = mkastnode(arithop(tokentype), left, right, 0);\n\n    // And get the next token at our precedence\n    tokentype = Token.token;\n    if (tokentype == T_EOF)\n      break;\n  }\n\n  // Return whatever tree we have created\n  return (left);\n}\n```\n\nRight at the beginning, we immediately call `multiplicative_expr()`\nin case the first operator is a high-precedence '*' or '/'. That\nfunction will only return when it encounters a low-precedence\n'+' or '-' operator.\n\nThus, when we hit the `while` loop, we know we have a '+' or '-' operator.\nWe loop until there are no tokens left in the input, i.e. when we hit\nthe T_EOF token.\n\nInside the loop, we call `multiplicative_expr()` again in case any\nfuture operators are higher precedence than us. Again, this will\nreturn when they are not.\n\nOnce we have a left and right sub-tree, we can combine them with\nthe operator we got the last time around the loop. This repeats, so that\nif we had the expression `2 + 4 + 6`, we would end up with the AST tree:\n\n``` \n       +\n      / \\\n     +   6\n    / \\\n   2   4\n```\n\nBut if `multiplicative_expr()` had its own higher precedence operators,\nwe would be combining sub-trees with multiple nodes in them.\n\n## multiplicative_expr()\n\n```c\n// Return an AST tree whose root is a '*' or '/' binary operator\nstruct ASTnode *multiplicative_expr(void) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the integer literal on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If no tokens left, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_EOF)\n    return (left);\n\n  // While the token is a '*' or '/'\n  while ((tokentype == T_STAR) || (tokentype == T_SLASH)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n    right = primary();\n\n    // Join that with the left integer literal\n    left = mkastnode(arithop(tokentype), left, right, 0);\n\n    // Update the details of the current token.\n    // If no tokens left, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_EOF)\n      break;\n  }\n\n  // Return whatever tree we have created\n  return (left);\n}\n```\n\nThe code is similar to `additive_expr()` except that we get to call\n`primary()` to get real integer literals! We also only loop when\nwe have operators at our high precedence level, i.e. '*' and '/'\noperators. As soon as we hit a low precedence operator, we simply\nreturn the sub-tree that we've built to this point. This goes\nback to `additive_expr()` to deal with the low precedence operator.\n\n## Drawbacks of the Above\n\nThe above way of constructing a recursive descent parser with\nexplicit operator precedence can be inefficient because of\nall the function calls needed to reach the right level of precedence.\nThere also has to be functions to deal with each level of operator\nprecedence, so we end up with lots of lines of code.\n\n## The Alternative: Pratt Parsing\n\nOne way to cut down on the amount of code is to use a\n[Pratt parser](https://en.wikipedia.org/wiki/Pratt_parser)\nwhich has a table of precedence values associated with each token\ninstead of having functions that replicate the explicit precedence in\nthe grammar.\n\nAt this point I highly recommend that you read\n[Pratt Parsers: Expression Parsing Made Easy](https://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/)\nby Bob Nystrom. Pratt parsers still make my head hurt, so read as much\nas you can and get comfortable with the basic concept.\n\n## `expr.c`: Pratt Parsing\n\nI've implemented Pratt parsing in `expr.c` which is a drop-in replacement\nfor `expr2.c`. Let's start the tour.\n\nFirstly, we need some code to determine the precedence levels for each\ntoken:\n\n```c\n// Operator precedence for each token\nstatic int OpPrec[] = { 0, 10, 10, 20, 20,    0 };\n//                     EOF  +   -   *   /  INTLIT\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0) {\n    fprintf(stderr, \"syntax error on line %d, token %d\\n\", Line, tokentype);\n    exit(1);\n  }\n  return (prec);\n}\n```\n\nHigher numbers (e.g. 20) mean a higher precedence than lower numbers\n(e.g. 10).\n\nNow, you might ask: why have a function when you have a look-up table called\n`OpPrec[]`? The answer is: to spot syntax errors.\n\nConsider an input that looks like `234 101 + 12`. We can scan in the\nfirst two tokens. But if we simply used `OpPrec[]` to get the precedence of the\nsecond `101` token, we wouldn't notice that it isn't an operator. Thus,\nthe `op_precedence()` function enforces the correct grammar syntax.\n\nNow, instead of having a function for each precedence level, we have a\nsingle expression function that uses the table of operator precedences:\n\n```c\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the integer literal on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If no tokens left, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_EOF)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left, right, 0);\n\n    // Update the details of the current token.\n    // If no tokens left, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_EOF)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n```\n\nFirstly, note that this is still recursive like the previous parser\nfunctions. This time, we receive the precedence level of the token\nthat was found before we got called. `main()` will call us with the\nlowest precedence, 0, but we will call ourselves with higher values.\n\nYou should also spot that the code is quite similar to the\n`multiplicative_expr()` function: read in an integer literal,\nget the operator's token type, then loop building a tree.\n\nThe difference is the loop condition and body:\n\n```c\nmultiplicative_expr():\n  while ((tokentype == T_STAR) || (tokentype == T_SLASH)) {\n    scan(&Token); right = primary();\n\n    left = mkastnode(arithop(tokentype), left, right, 0);\n\n    tokentype = Token.token;\n    if (tokentype == T_EOF) return (left);\n  }\n\nbinexpr():\n  while (op_precedence(tokentype) > ptp) {\n    scan(&Token); right = binexpr(OpPrec[tokentype]);\n\n    left = mkastnode(arithop(tokentype), left, right, 0);\n\n    tokentype = Token.token;\n    if (tokentype == T_EOF) return (left);\n  }\n```\n\nWith the Pratt parser, when the next operator has a higher precedence\nthan our current token, instead of just getting the next integer\nliteral with `primary()`, we call ourselves with `binexpr(OpPrec[tokentype])`\nto raise the operator precedence.\n\nOnce we hit a token at our precedence level or lower, we will simply:\n\n```c\n  return (left);\n```\n\nThis will either be a sub-tree with lots of nodes and operators at\na higher precedence that the operator that called us, or it might\nbe a single integer literal for an operator at the same predence as us.\n\nNow we have a single function to do expression parsing. It uses a\nsmall helper function to enforce the operator precedence, and thus\nimplements the semantics of our language.\n\n## Putting Both Parsers Into Action\n\nYou can make two programs, one with each parser:\n\n```\n$ make parser                                        # Pratt Parser\ncc -o parser -g expr.c interp.c main.c scan.c tree.c\n\n$ make parser2                                       # Precedence Climbing\ncc -o parser2 -g expr2.c interp.c main.c scan.c tree.c\n```\n\nYou can also test both parsers with the same input files from the\nprevious part of our journey:\n\n```\n$ make test\n(./parser input01; \\\n ./parser input02; \\\n ./parser input03; \\\n ./parser input04; \\\n ./parser input05)\n15                                       # input01 result\n29                                       # input02 result\nsyntax error on line 1, token 5          # input03 result\nUnrecognised character . on line 3       # input04 result\nUnrecognised character a on line 1       # input05 result\n\n$ make test2\n(./parser2 input01; \\\n ./parser2 input02; \\\n ./parser2 input03; \\\n ./parser2 input04; \\\n ./parser2 input05)\n15                                       # input01 result\n29                                       # input02 result\nsyntax error on line 1, token 5          # input03 result\nUnrecognised character . on line 3       # input04 result\nUnrecognised character a on line 1       # input05 result\n\n```\n\n## Conclusion and What's Next\n\nIt's probably time to step back a bit and see where we've got to. We now have:\n\n + a scanner that recognises and returns the tokens in our language\n + a parser that recognises our grammar, reports syntax errors and\n   builds an Abstract Syntax Tree\n + a precedence table for the parser that implements the semantics of\n   our language\n + an interpreter that traverses the Abstract Syntax Tree depth-first\n   and calculates the result of the expression in the input\n\nWhat we don't have yet is a compiler. But we are so close to making our\nfirst compiler!\n\nIn the next part of our compiler writing journey, we will replace the\ninterpreter. In its place, we will write a translator that generates\nx86-64 assembly code for each AST node that has a maths operator.\nWe will also generate some assembly preamble and postamble to\nsupport the assembly code that the generator outputs. [Next step](../04_Assembly/Readme.md)\n"
  },
  {
    "path": "03_Precedence/data.h",
    "content": "#ifndef extern_\n #define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int     \tLine;\nextern_ int\t\tPutback;\nextern_ FILE\t\t*Infile;\nextern_ struct token\tToken;\n"
  },
  {
    "path": "03_Precedence/decl.h",
    "content": "\n// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\nint scan(struct token *t);\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int intvalue);\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue);\nstruct ASTnode *binexpr(int rbp);\nint interpretAST(struct ASTnode *n);\n"
  },
  {
    "path": "03_Precedence/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Token types\nenum {\n  T_EOF, T_PLUS, T_MINUS, T_STAR, T_SLASH, T_INTLIT\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types\nenum {\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_INTLIT\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t\t// \"Operation\" to be performed on this tree\n  struct ASTnode *left;\t\t\t// Left and right child trees\n  struct ASTnode *right;\n  int intvalue;\t\t\t\t// For A_INTLIT, the integer value\n};\n"
  },
  {
    "path": "03_Precedence/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n\n  // For an INTLIT token, make a leaf AST node for it\n  // and scan in the next token. Otherwise, a syntax error\n  // for any other token type.\n  switch (Token.token) {\n  case T_INTLIT:\n    n = mkastleaf(A_INTLIT, Token.intvalue);\n    scan(&Token);\n    return (n);\n  default:\n    fprintf(stderr, \"syntax error on line %d, token %d\\n\", Line, Token.token);\n    exit(1);\n  }\n}\n\n\n// Convert a binary operator token into an AST operation.\nint arithop(int tokentype) {\n  switch (tokentype) {\n  case T_PLUS:\n    return (A_ADD);\n  case T_MINUS:\n    return (A_SUBTRACT);\n  case T_STAR:\n    return (A_MULTIPLY);\n  case T_SLASH:\n    return (A_DIVIDE);\n  default:\n    fprintf(stderr, \"syntax error on line %d, token %d\\n\", Line, tokentype);\n    exit(1);\n  }\n}\n\n// Operator precedence for each token\nstatic int OpPrec[] = { 0, 10, 10, 20, 20, 0 };\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0) {\n    fprintf(stderr, \"syntax error on line %d, token %d\\n\", Line, tokentype);\n    exit(1);\n  }\n  return (prec);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the integer literal on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If no tokens left, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_EOF)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left, right, 0);\n\n    // Update the details of the current token.\n    // If no tokens left, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_EOF)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "03_Precedence/expr2.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions with full recursive descent\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n\n  // For an INTLIT token, make a leaf AST node for it\n  // and scan in the next token. Otherwise, a syntax error\n  // for any other token type.\n  switch (Token.token) {\n  case T_INTLIT:\n    n = mkastleaf(A_INTLIT, Token.intvalue);\n    scan(&Token);\n    return (n);\n  default:\n    fprintf(stderr, \"syntax error on line %d, token %d\\n\", Line, Token.token);\n    exit(1);\n  }\n}\n\n\n// Convert a binary operator token into an AST operation.\nstatic int arithop(int tok) {\n  switch (tok) {\n  case T_PLUS:\n    return (A_ADD);\n  case T_MINUS:\n    return (A_SUBTRACT);\n  case T_STAR:\n    return (A_MULTIPLY);\n  case T_SLASH:\n    return (A_DIVIDE);\n  default:\n    fprintf(stderr, \"syntax error on line %d, token %d\\n\", Line, tok);\n    exit(1);\n  }\n}\n\nstruct ASTnode *additive_expr(void);\n\n// Return an AST tree whose root is a '*' or '/' binary operator\nstruct ASTnode *multiplicative_expr(void) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the integer literal on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If no tokens left, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_EOF)\n    return (left);\n\n  // While the token is a '*' or '/'\n  while ((tokentype == T_STAR) || (tokentype == T_SLASH)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n    right = primary();\n\n    // Join that with the left integer literal\n    left = mkastnode(arithop(tokentype), left, right, 0);\n\n    // Update the details of the current token.\n    // If no tokens left, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_EOF)\n      break;\n  }\n\n  // Return whatever tree we have created\n  return (left);\n}\n\n// Return an AST tree whose root is a '+' or '-' binary operator\nstruct ASTnode *additive_expr(void) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the left sub-tree at a higher precedence than us\n  left = multiplicative_expr();\n\n  // If no tokens left, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_EOF)\n    return (left);\n\n  // Cache the '+' or '-' token type\n\n  // Loop working on token at our level of precedence\n  while (1) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Get the right sub-tree at a higher precedence than us\n    right = multiplicative_expr();\n\n    // Join the two sub-trees with our low-precedence operator\n    left = mkastnode(arithop(tokentype), left, right, 0);\n\n    // And get the next token at our precedence\n    tokentype = Token.token;\n    if (tokentype == T_EOF)\n      break;\n  }\n\n  // Return whatever tree we have created\n  return (left);\n}\n\nstruct ASTnode *binexpr(int n) {\n  return (additive_expr());\n}\n"
  },
  {
    "path": "03_Precedence/input01",
    "content": "2 + 3 * 5 - 8 / 3\n"
  },
  {
    "path": "03_Precedence/input02",
    "content": "13 -6+  4*\n5\n       +\n08 / 3\n"
  },
  {
    "path": "03_Precedence/input03",
    "content": "12 34 + -56 * / - - 8 + * 2\n"
  },
  {
    "path": "03_Precedence/input04",
    "content": "23 +\n18 -\n45.6 * 2\n/ 18\n"
  },
  {
    "path": "03_Precedence/input05",
    "content": "23 * 456abcdefg\n"
  },
  {
    "path": "03_Precedence/interp.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree interpreter\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// List of AST operators\nstatic char *ASTop[] = { \"+\", \"-\", \"*\", \"/\" };\n\n// Given an AST, interpret the\n// operators in it and return\n// a final value.\nint interpretAST(struct ASTnode *n) {\n  int leftval, rightval;\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftval = interpretAST(n->left);\n  if (n->right)\n    rightval = interpretAST(n->right);\n\n  // Debug: Print what we are about to do\n  // if (n->op == A_INTLIT)\n  //   printf(\"int %d\\n\", n->intvalue);\n  // else\n  //   printf(\"%d %s %d\\n\", leftval, ASTop[n->op], rightval);\n\n  switch (n->op) {\n    case A_ADD:\n      return (leftval + rightval);\n    case A_SUBTRACT:\n      return (leftval - rightval);\n    case A_MULTIPLY:\n      return (leftval * rightval);\n    case A_DIVIDE:\n      return (leftval / rightval);\n    case A_INTLIT:\n      return (n->intvalue);\n    default:\n      fprintf(stderr, \"Unknown AST operator %d\\n\", n->op);\n      exit(1);\n  }\n}\n"
  },
  {
    "path": "03_Precedence/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nvoid main(int argc, char *argv[]) {\n  struct ASTnode *n;\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  n = binexpr(0);\t\t// Parse the expression in the file\n  printf(\"%d\\n\", interpretAST(n));\t// Calculate the final result\n  exit(0);\n}\n"
  },
  {
    "path": "03_Precedence/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return c;\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return c;\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return val;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c;\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n  case EOF:\n    t->token = T_EOF;\n    return (0);\n  case '+':\n    t->token = T_PLUS;\n    break;\n  case '-':\n    t->token = T_MINUS;\n    break;\n  case '*':\n    t->token = T_STAR;\n    break;\n  case '/':\n    t->token = T_SLASH;\n    break;\n  default:\n\n    // If it's a digit, scan the\n    // literal integer value in\n    if (isdigit(c)) {\n      t->intvalue = scanint(c);\n      t->token = T_INTLIT;\n      break;\n    }\n\n    printf(\"Unrecognised character %c on line %d\\n\", c, Line);\n    exit(1);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "03_Precedence/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL) {\n    fprintf(stderr, \"Unable to malloc in mkastnode()\\n\");\n    exit(1);\n  }\n  // Copy in the field values and return it\n  n->op = op;\n  n->left = left;\n  n->right = right;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int intvalue) {\n  return (mkastnode(op, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue) {\n  return (mkastnode(op, left, NULL, intvalue));\n}\n"
  },
  {
    "path": "04_Assembly/Makefile",
    "content": "comp1: cg.c expr.c gen.c interp.c main.c scan.c tree.c\n\tcc -o comp1 -g cg.c expr.c gen.c interp.c main.c scan.c tree.c\n\ncompn: cgn.c expr.c gen.c interp.c main.c scan.c tree.c\n\tcc -o compn -g cgn.c expr.c gen.c interp.c main.c scan.c tree.c\n\nclean:\n\trm -f comp1 compn *.o *.s out\n\ntest: comp1\n\t./comp1 input01\n\tcc -o out out.s\n\t./out\n\t./comp1 input02\n\tcc -o out out.s\n\t./out\n\ntestn: compn\n\t./compn input01\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out out.o\n\t./out\n\t./compn input02\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out out.o\n\t./out\n"
  },
  {
    "path": "04_Assembly/Readme.md",
    "content": "# Part 4: An Actual Compiler\n\nIt's about time that I met my promise of actually writing a compiler.\nSo in this part of the journey we are going to replace the interpreter\nin our program with code that generates x86-64 assembly code.\n\n## Revising the Interpreter\n\nBefore we do, it will be worthwhile to revisit the interpreter code\nin `interp.c`:\n\n```c\nint interpretAST(struct ASTnode *n) {\n  int leftval, rightval;\n\n  if (n->left) leftval = interpretAST(n->left);\n  if (n->right) rightval = interpretAST(n->right);\n\n  switch (n->op) {\n    case A_ADD:      return (leftval + rightval);\n    case A_SUBTRACT: return (leftval - rightval);\n    case A_MULTIPLY: return (leftval * rightval);\n    case A_DIVIDE:   return (leftval / rightval);\n    case A_INTLIT:   return (n->intvalue);\n\n    default:\n      fprintf(stderr, \"Unknown AST operator %d\\n\", n->op);\n      exit(1);\n  }\n}\n```\n\nThe `interpretAST()` function walks the given AST tree depth-first.\nIt evaluates any left sub-tree, then the right sub-tree. Finally, it\nuses the `op` value at the base of the current tree to operate on\nthese children.\n\nIf the `op` value is one of the four maths operators, then this maths\noperation is performed. If the `op` value indicates that the node\nis simply an integer literal, the literal value is return.\n\nThe function returns the final value for this tree. And, as it is\nrecursive, it will calculate the final value for a whole tree\none sub-sub-tree at a time.\n\n## Changing to Assembly Code Generation\n\nWe are going to write an assembly code generator which is generic.\nThis is, in turn, going to call out to a set of CPU-specific code\ngeneration functions.\n\nHere is the generic assembly code generator in `gen.c`:\n\n```c\n// Given an AST, generate\n// assembly code recursively\nstatic int genAST(struct ASTnode *n) {\n  int leftreg, rightreg;\n\n  // Get the left and right sub-tree values\n  if (n->left) leftreg = genAST(n->left);\n  if (n->right) rightreg = genAST(n->right);\n\n  switch (n->op) {\n    case A_ADD:      return (cgadd(leftreg,rightreg));\n    case A_SUBTRACT: return (cgsub(leftreg,rightreg));\n    case A_MULTIPLY: return (cgmul(leftreg,rightreg));\n    case A_DIVIDE:   return (cgdiv(leftreg,rightreg));\n    case A_INTLIT:   return (cgload(n->intvalue));\n\n    default:\n      fprintf(stderr, \"Unknown AST operator %d\\n\", n->op);\n      exit(1);\n  }\n}\n```\n\nLooks familar, huh?! We are doing the same depth-first tree traversal.\nThis time:\n\n  + A_INTLIT: load a register with the literal value\n  + Other operators: perform a maths function on the two registers\n    that hold the left-child's and right-child's value\n\nInstead of passing values, the code in `genAST()` passes around\nregister identifiers. For example `cgload()` loads a value into a register and\nreturns the identity of the register with the loaded value.\n\n`genAST()` itself returns the identity of the register that holds the final\nvalue of the tree at this point. That's why the code at the top is\ngetting register identities:\n\n```c\n  if (n->left) leftreg = genAST(n->left);\n  if (n->right) rightreg = genAST(n->right);\n```\n\n## Calling `genAST()`\n\n`genAST()` is only going to calculate the value of the expression given to\nit. We need to print out this final calculation. We're also going to need\nto wrap the assembly code we generate with some leading code (the\n*preamble*) and some trailing code (the *postamble*). This is done with\nthe other function in `gen.c`:\n\n```c\nvoid generatecode(struct ASTnode *n) {\n  int reg;\n\n  cgpreamble();\n  reg= genAST(n);\n  cgprintint(reg);      // Print the register with the result as an int\n  cgpostamble();\n}\n```\n\n## The x86-64 Code Generator\n\nThat's the generic code generator out of the road. Now we need to look\nat the generation of some real assembly code. For now, I'm targetting\nthe x86-64 CPU as this is still one of the most common Linux platforms.\nSo, open up `cg.c` and let's get browsing.\n\n### Allocating Registers\n\nAny CPU has a limited number of registers. We will have to allocate\na register to hold the integer literal values, plus any calculation\nthat we perform on them. However, once we've used a value, we can\noften discard the value and hence free up the register holding it.\nThen we can re-use that register for another value.\n\nThere are three functions that deal with register allocation:\n\n + `freeall_registers()`: Set all registers as available\n + `alloc_register()`: Allocate a free register\n + `free_register()`: Free an allocated register\n\nI'm not going to go through the code as it's straight forward but with\nsome error checking. Right now, if I run out of registers then the\nprogram will crash. Later on, I'll deal with the situation when we have\nrun out of free registers.\n\nThe code works on generic registers: r0, r1, r2 and r3. There is a table\nof strings with the actual register names:\n\n```c\nstatic char *reglist[4]= { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\n```\n\nThis makes these functions fairly independent of the CPU architecture.\n\n### Loading a Register\n\nThis is done in `cgload()`: a register is allocated, then a `movq`\ninstruction loads a literal value into the allocated register.\n\n```c\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgload(int value) {\n\n  // Get a new register\n  int r= alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return(r);\n}\n```\n\n### Adding Two Registers\n\n`cgadd()` takes two register numbers and generates the code to add\nthem together. The result is saved in one of the two registers,\nand the other one is then freed for future use:\n\n```c\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return(r2);\n}\n```\n\nNote that addition is *commutative*, so I could have added `r2` to `r1`\ninstead of `r1` to `r2`. The identity of the register with the final\nvalue is returned.\n\n### Multiplying Two Registers\n\nThis is very similar to addition, and again the operation is\n*commutative*, so any register can be returned:\n\n```c\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return(r2);\n}\n```\n\n### Subtracting Two Registers\n\nSubtraction is *not* commutative: we have to get the order correct.\nThe second register is subtracted from the first, so we return the\nfirst and free the second:\n\n```c\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return(r1);\n}\n```\n\n### Dividing Two Registers\n\nDivision is also not commutative, so the previous notes apply. On\nthe x86-64, it's even more complicated. We need to load `%rax`\nwith the *dividend* from `r1`. This needs to be extended to eight\nbytes with `cqo`. Then, `idivq` will divide `%rax` with the divisor\nin `r2`, leaving the *quotient* in `%rax`, so we need to copy it\nout to either `r1` or `r2`. Then we can free the other register.\n\n```c\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return(r1);\n}\n```\n\n### Printing A Register\n\nThere isn't an x86-64 instruction to print a register out as a decimal\nnumber. To solve this problem, the assembly preamble contains a function\ncalled `printint()` that takes a register argument and calls `printf()`\nto print this out in decimal.\n\nI'm not going to give the code in `cgpreamble()`, but it also contains\nthe beginning code for `main()`, so that we can assemble our output file\nto get a complete program. The code for `cgpostamble()`, also not given\nhere, simply calls `exit(0)` to end the program.\n\nHere, however, is `cgprintint()`:\n\n```c\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n```\n\nLinux x86-64 expects the first argument to a function to be in the `%rdi`\nregister, so we move our register into `%rdi` before we `call printint`.\n\n## Doing Our First Compile\n\nThat's about it for the x86-64 code generator. There is some extra code\nin `main()` to open out `out.s` as our output file. I've also left the\ninterpreter in the program so we can confirm that our assembly calculates\nthe same answer for the input expression as the interpreter.\n\nLet's make the compiler and run it on `input01`:\n\n```make\n$ make\ncc -o comp1 -g cg.c expr.c gen.c interp.c main.c scan.c tree.c\n\n$ make test\n./comp1 input01\n15\ncc -o out out.s\n./out\n15\n```\n\nYes! The first 15 is the interpreter's output. The second 15 is the\nassembly's output.\n\n## Examining the Assembly Output\n\nSo, exactly what was the assembly output? Well, here is the input file:\n\n```\n2 + 3 * 5 - 8 / 3\n```\n\nand here is `out.s` for this input with comments:\n\n```\n        .text                           # Preamble code\n.LC0:\n        .string \"%d\\n\"                  # \"%d\\n\" for printf()\nprintint:\n        pushq   %rbp\n        movq    %rsp, %rbp              # Set the frame pointer\n        subq    $16, %rsp\n        movl    %edi, -4(%rbp)\n        movl    -4(%rbp), %eax          # Get the printint() argument\n        movl    %eax, %esi\n        leaq    .LC0(%rip), %rdi        # Get the pointer to \"%d\\n\"\n        movl    $0, %eax\n        call    printf@PLT              # Call printf()\n        nop\n        leave                           # and return\n        ret\n\n        .globl  main\n        .type   main, @function\nmain:\n        pushq   %rbp\n        movq    %rsp, %rbp              # Set the frame pointer\n                                        # End of preamble code\n\n        movq    $2, %r8                 # %r8 = 2\n        movq    $3, %r9                 # %r9 = 3\n        movq    $5, %r10                # %r10 = 5\n        imulq   %r9, %r10               # %r10 = 3 * 5 = 15\n        addq    %r8, %r10               # %r10 = 2 + 15 = 17\n                                        # %r8 and %r9 are now free again\n        movq    $8, %r8                 # %r8 = 8\n        movq    $3, %r9                 # %r9 = 3\n        movq    %r8,%rax\n        cqo                             # Load dividend %rax with 8\n        idivq   %r9                     # Divide by 3\n        movq    %rax,%r8                # Store quotient in %r8, i.e. 2\n        subq    %r8, %r10               # %r10 = 17 - 2 = 15\n        movq    %r10, %rdi              # Copy 15 into %rdi in preparation\n        call    printint                # to call printint()\n\n        movl    $0, %eax                # Postamble: call exit(0)\n        popq    %rbp\n        ret\n```\n\nExcellent! We now have a legitimate compiler: a program that takes\nan input in one language and generates a translation of that input\nin another language.\n\nWe still have to then assemble the output down to machine code and link\nit with the support libraries, but this is something that we can\nperform manually for now. Later on, we will write some code to do\nthis automatically.\n\n## Conclusion and What's Next\n\nChanging from the interpreter to a generic code generator was trivial, but then\nwe had to write some code to generate real assembly output. To do this,\nwe had to think about how to allocate registers: for now, we have a naive\nsolution. We also had to deal with some x86-64 oddities like the `idivq`\ninstruction.\n\nSomething I haven't touched on yet is: why bother with generating the AST for\nan expression? Surely, we could have called `cgadd()` when we hit a '+'\ntoken in our Pratt parser, ditto for the other operators. I'm going to\nleave you to think about this, but I will come back to it in a step or\ntwo.\n\nIn the next part of our compiler writing journey, we will add some\nstatements to our language, so that it starts to resemble a proper\ncomputer language. [Next step](../05_Statements/Readme.md)\n"
  },
  {
    "path": "04_Assembly/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers\n// and their names\nstatic int freereg[4];\nstatic char *reglist[4]= { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\n\n// Set all registers as available\nvoid freeall_registers(void)\n{\n  freereg[0]= freereg[1]= freereg[2]= freereg[3]= 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void)\n{\n  for (int i=0; i<4; i++) {\n    if (freereg[i]) {\n      freereg[i]= 0;\n      return(i);\n    }\n  }\n  fprintf(stderr, \"Out of registers!\\n\");\n  exit(1);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg)\n{\n  if (freereg[reg] != 0) {\n    fprintf(stderr, \"Error trying to free register %d\\n\", reg);\n    exit(1);\n  }\n  freereg[reg]= 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble()\n{\n  freeall_registers();\n  fputs(\n\t\"\\t.text\\n\"\n\t\".LC0:\\n\"\n\t\"\\t.string\\t\\\"%d\\\\n\\\"\\n\"\n\t\"printint:\\n\"\n\t\"\\tpushq\\t%rbp\\n\"\n\t\"\\tmovq\\t%rsp, %rbp\\n\"\n\t\"\\tsubq\\t$16, %rsp\\n\"\n\t\"\\tmovl\\t%edi, -4(%rbp)\\n\"\n\t\"\\tmovl\\t-4(%rbp), %eax\\n\"\n\t\"\\tmovl\\t%eax, %esi\\n\"\n\t\"\\tleaq\t.LC0(%rip), %rdi\\n\"\n\t\"\\tmovl\t$0, %eax\\n\"\n\t\"\\tcall\tprintf@PLT\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"\\t.globl\\tmain\\n\"\n\t\"\\t.type\\tmain, @function\\n\"\n\t\"main:\\n\"\n\t\"\\tpushq\\t%rbp\\n\"\n\t\"\\tmovq\t%rsp, %rbp\\n\",\n  Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble()\n{\n  fputs(\n\t\"\\tmovl\t$0, %eax\\n\"\n\t\"\\tpopq\t%rbp\\n\"\n\t\"\\tret\\n\",\n  Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgload(int value) {\n\n  // Get a new register\n  int r= alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return(r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return(r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return(r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return(r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return(r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n"
  },
  {
    "path": "04_Assembly/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers\n// and their names\nstatic int freereg[4];\nstatic char *reglist[4]= { \"r8\", \"r9\", \"r10\", \"r11\" };\n\n// Set all registers as available\nvoid freeall_registers(void)\n{\n  freereg[0]= freereg[1]= freereg[2]= freereg[3]= 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void)\n{\n  for (int i=0; i<4; i++) {\n    if (freereg[i]) {\n      freereg[i]= 0;\n      return(i);\n    }\n  }\n  fprintf(stderr, \"Out of registers!\\n\");\n  exit(1);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg)\n{\n  if (freereg[reg] != 0) {\n    fprintf(stderr, \"Error trying to free register %d\\n\", reg);\n    exit(1);\n  }\n  freereg[reg]= 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble()\n{\n  freeall_registers();\n  fputs(\n\t\"\\tglobal\\tmain\\n\"\n\t\"\\textern\\tprintf\\n\"\n\t\"\\tsection\\t.text\\n\"\n\t\"LC0:\\tdb\\t\\\"%d\\\",10,0\\n\"\n\t\"printint:\\n\"\n\t\"\\tpush\\trbp\\n\"\n\t\"\\tmov\\trbp, rsp\\n\"\n\t\"\\tsub\\trsp, 16\\n\"\n\t\"\\tmov\\t[rbp-4], edi\\n\"\n\t\"\\tmov\\teax, [rbp-4]\\n\"\n\t\"\\tmov\\tesi, eax\\n\"\n\t\"\\tlea\trdi, [rel LC0]\\n\"\n\t\"\\tmov\teax, 0\\n\"\n\t\"\\tcall\tprintf\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"main:\\n\"\n\t\"\\tpush\\trbp\\n\"\n\t\"\\tmov\trbp, rsp\\n\",\n  Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble()\n{\n  fputs(\n\t\"\\tmov\teax, 0\\n\"\n\t\"\\tpop\trbp\\n\"\n\t\"\\tret\\n\",\n  Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgload(int value) {\n\n  // Get a new register\n  int r= alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return(r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return(r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return(r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return(r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return(r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n"
  },
  {
    "path": "04_Assembly/data.h",
    "content": "#ifndef extern_\n #define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int     \tLine;\nextern_ int\t\tPutback;\nextern_ FILE\t\t*Infile;\nextern_ FILE\t\t*Outfile;\nextern_ struct token\tToken;\n"
  },
  {
    "path": "04_Assembly/decl.h",
    "content": "\n// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\nint scan(struct token *t);\n\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int intvalue);\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue);\nstruct ASTnode *binexpr(int rbp);\n\nint interpretAST(struct ASTnode *n);\nvoid generatecode(struct ASTnode *n);\n\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nint cgload(int value);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nvoid cgprintint(int r);\n"
  },
  {
    "path": "04_Assembly/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Token types\nenum {\n  T_EOF, T_PLUS, T_MINUS, T_STAR, T_SLASH, T_INTLIT\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types\nenum {\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_INTLIT\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t\t// \"Operation\" to be performed on this tree\n  struct ASTnode *left;\t\t\t// Left and right child trees\n  struct ASTnode *right;\n  int intvalue;\t\t\t\t// For A_INTLIT, the integer value\n};\n"
  },
  {
    "path": "04_Assembly/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n\n  // For an INTLIT token, make a leaf AST node for it\n  // and scan in the next token. Otherwise, a syntax error\n  // for any other token type.\n  switch (Token.token) {\n  case T_INTLIT:\n    n = mkastleaf(A_INTLIT, Token.intvalue);\n    scan(&Token);\n    return (n);\n  default:\n    fprintf(stderr, \"syntax error on line %d, token %d\\n\", Line, Token.token);\n    exit(1);\n  }\n}\n\n\n// Convert a binary operator token into an AST operation.\nint arithop(int tokentype) {\n  switch (tokentype) {\n  case T_PLUS:\n    return (A_ADD);\n  case T_MINUS:\n    return (A_SUBTRACT);\n  case T_STAR:\n    return (A_MULTIPLY);\n  case T_SLASH:\n    return (A_DIVIDE);\n  default:\n    fprintf(stderr, \"syntax error on line %d, token %d\\n\", Line, tokentype);\n    exit(1);\n  }\n}\n\n// Operator precedence for each token\nstatic int OpPrec[] = { 0, 10, 10, 20, 20, 0 };\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0) {\n    fprintf(stderr, \"syntax error on line %d, token %d\\n\", Line, tokentype);\n    exit(1);\n  }\n  return (prec);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the integer literal on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If no tokens left, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_EOF)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left, right, 0);\n\n    // Update the details of the current token.\n    // If no tokens left, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_EOF)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "04_Assembly/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given an AST, generate\n// assembly code recursively\nstatic int genAST(struct ASTnode *n) {\n  int leftreg, rightreg;\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left);\n  if (n->right)\n    rightreg = genAST(n->right);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg,rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg,rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg,rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg,rightreg));\n    case A_INTLIT:\n      return (cgload(n->intvalue));\n    default:\n      fprintf(stderr, \"Unknown AST operator %d\\n\", n->op);\n      exit(1);\n  }\n}\n\nvoid generatecode(struct ASTnode *n) {\n  int reg;\n\n  cgpreamble();\n  reg= genAST(n);\n  cgprintint(reg);\n  cgpostamble();\n}\n"
  },
  {
    "path": "04_Assembly/input01",
    "content": "2 + 3 * 5 - 8 / 3\n"
  },
  {
    "path": "04_Assembly/input02",
    "content": "13 -6+  4*\n5\n       +\n08 / 3\n"
  },
  {
    "path": "04_Assembly/interp.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree interpreter\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// List of AST operators\nstatic char *ASTop[] = { \"+\", \"-\", \"*\", \"/\" };\n\n// Given an AST, interpret the\n// operators in it and return\n// a final value.\nint interpretAST(struct ASTnode *n) {\n  int leftval, rightval;\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftval = interpretAST(n->left);\n  if (n->right)\n    rightval = interpretAST(n->right);\n\n  // Debug: Print what we are about to do\n  // if (n->op == A_INTLIT)\n  //   printf(\"int %d\\n\", n->intvalue);\n  // else\n  //   printf(\"%d %s %d\\n\", leftval, ASTop[n->op], rightval);\n\n  switch (n->op) {\n    case A_ADD:\n      return (leftval + rightval);\n    case A_SUBTRACT:\n      return (leftval - rightval);\n    case A_MULTIPLY:\n      return (leftval * rightval);\n    case A_DIVIDE:\n      return (leftval / rightval);\n    case A_INTLIT:\n      return (n->intvalue);\n    default:\n      fprintf(stderr, \"Unknown AST operator %d\\n\", n->op);\n      exit(1);\n  }\n}\n"
  },
  {
    "path": "04_Assembly/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nvoid main(int argc, char *argv[]) {\n  struct ASTnode *n;\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  n = binexpr(0);\t\t// Parse the expression in the file\n  printf(\"%d\\n\", interpretAST(n));\t// Calculate the final result\n  generatecode(n);\n\n  fclose(Outfile);\n  exit(0);\n}\n"
  },
  {
    "path": "04_Assembly/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return c;\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return c;\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return val;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c;\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n  case EOF:\n    t->token = T_EOF;\n    return (0);\n  case '+':\n    t->token = T_PLUS;\n    break;\n  case '-':\n    t->token = T_MINUS;\n    break;\n  case '*':\n    t->token = T_STAR;\n    break;\n  case '/':\n    t->token = T_SLASH;\n    break;\n  default:\n\n    // If it's a digit, scan the\n    // literal integer value in\n    if (isdigit(c)) {\n      t->intvalue = scanint(c);\n      t->token = T_INTLIT;\n      break;\n    }\n\n    printf(\"Unrecognised character %c on line %d\\n\", c, Line);\n    exit(1);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "04_Assembly/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL) {\n    fprintf(stderr, \"Unable to malloc in mkastnode()\\n\");\n    exit(1);\n  }\n  // Copy in the field values and return it\n  n->op = op;\n  n->left = left;\n  n->right = right;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int intvalue) {\n  return (mkastnode(op, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue) {\n  return (mkastnode(op, left, NULL, intvalue));\n}\n"
  },
  {
    "path": "05_Statements/Makefile",
    "content": "comp1: cg.c expr.c gen.c main.c misc.c scan.c stmt.c tree.c\n\tcc -o comp1 -g cg.c expr.c gen.c main.c misc.c scan.c stmt.c tree.c\n\ncompn: cgn.c expr.c gen.c main.c misc.c scan.c stmt.c tree.c\n\tcc -o compn -g cgn.c expr.c gen.c main.c misc.c scan.c stmt.c tree.c\n\nclean:\n\trm -f comp1 compn *.o *.s out\n\ntest: comp1 input01\n\t./comp1 input01\n\tcc -o out out.s\n\t./out\n\ntestn: compn input01\n\t./compn input01\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out out.o\n\t./out\n"
  },
  {
    "path": "05_Statements/Readme.md",
    "content": "# Part 5: Statements\n\nIt's time to add some \"proper\" statements to the grammar of our language.\nI want to be able to write lines of code like this:\n\n```\n   print 2 + 3 * 5;\n   print 18 - 6/3 + 4*2;\n```\n\nOf course, as we are ignoring whitespace, there's no necessity that\nall the tokens for one statement are on the same line. Each statement\nstarts with the keyword `print` and is terminated with a semicolon. So\nthese are going to become new tokens in our language.\n\n## BNF Description of the Grammar\n\nWe've already seen the BNF notation  for expressions. Now let's define\nthe BNF syntax for the above types of statements:\n\n```\nstatements: statement\n     | statement statements\n     ;\n\nstatement: 'print' expression ';'\n     ;\n```\n\nAn input file consists of several statements. They are either one statement,\nor a statement followed by more statements. Each statement starts with the\nkeyword `print`, then one expression, then a semicolon.\n\n## Changes to the Lexical Scanner\n\nBefore we can get to the code that parses the above syntax, we need to\nadd a few more bits and pieces to the existing code. Let's start with\nthe lexical scanner.\n\nAdding a token for semicolons will be easy. Now, the `print` keyword.\nLater on, we'll have many keywords in the language, plus identifiers\nfor our variables, so we'll need to add some code which helps us to\ndeal with them.\n\nIn `scan.c`, I've added this code which I've borrowed from the SubC\ncompiler. It reads in alphanumeric characters into a \nbuffer until it hits a non-alphanumeric character.\n\n```c\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      printf(\"identifier too long on line %d\\n\", Line);\n      exit(1);\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n```\n\nWe also need a function to recognise keywords in the language. One way\nwould be to have a list of keywords, and to walk the list and `strcmp()`\neach one against the buffer from `scanident()`. The code from SubC has\nan optimisation: match against the first letter before doing the `strcmp()`.\nThis speeds up the comparison against dozens of keywords. Right now we\ndon't need this optimisation but I've put it in for later:\n\n```c\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'p':\n      if (!strcmp(s, \"print\"))\n        return (T_PRINT);\n      break;\n  }\n  return (0);\n}\n```\n\nNow, at the bottom of the switch statement in `scan()`, we add this code\nto recognise semicolons and keywords:\n\n```c\n    case ';':\n      t->token = T_SEMI;\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n        t->intvalue = scanint(c);\n        t->token = T_INTLIT;\n        break;\n      } else if (isalpha(c) || '_' == c) {\n        // Read in a keyword or identifier\n        scanident(c, Text, TEXTLEN);\n\n        // If it's a recognised keyword, return that token\n        if (tokentype = keyword(Text)) {\n          t->token = tokentype;\n          break;\n        }\n        // Not a recognised keyword, so an error for now\n        printf(\"Unrecognised symbol %s on line %d\\n\", Text, Line);\n        exit(1);\n      }\n      // The character isn't part of any recognised token, error\n      printf(\"Unrecognised character %c on line %d\\n\", c, Line);\n      exit(1);\n```\n\nI've also added a global `Text` buffer to store the keywords and\nidentifiers:\n\n```c\n#define TEXTLEN         512             // Length of symbols in input\nextern_ char Text[TEXTLEN + 1];         // Last identifier scanned\n```\n\n## Changes to the Expression Parser\n\nUp to now our input files have contained just a single expression; therefore,\nin our Pratt parser code in `binexpr()` (in `expr.c`), we had this code to\nexit the parser:\n\n```c\n  // If no tokens left, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_EOF)\n    return (left);\n```\n\nWith our new grammar, each expression is terminated by a semicolon. Thus,\nwe need to change the code in the expression parser to spot the `T_SEMI`\ntokens and exit the expression parsing:\n\n```c\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the integer literal on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If we hit a semicolon, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI)\n    return (left);\n\n    while (op_precedence(tokentype) > ptp) {\n      ...\n\n          // Update the details of the current token.\n    // If we hit a semicolon, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI)\n      return (left);\n    }\n}\n```\n\n## Changes to the Code Generator\n\nI want to keep the generic code generator in `gen.c`\nseparate from the CPU-specific code in `cg.c`. That also means\nthat the rest of the compiler should only ever call the functions in\n`gen.c`, and only `gen.c` should call the code in `cg.c`.\n\nTo this end, I've defined some new \"front-end\" functions in `gen.c`:\n\n```c\nvoid genpreamble()        { cgpreamble(); }\nvoid genpostamble()       { cgpostamble(); }\nvoid genfreeregs()        { freeall_registers(); }\nvoid genprintint(int reg) { cgprintint(reg); }\n```\n\n## Adding the Parser for Statements\n\nWe have a new file `stmt.c`. This will hold the parsing code for all\nthe main statements in our language. Right now, we need to parse the\nBNF grammar for statements which I gave up above. This is done with\nthis single function. I've converted the recursive definition into\na loop:\n\n```c\n// Parse one or more statements\nvoid statements(void) {\n  struct ASTnode *tree;\n  int reg;\n\n  while (1) {\n    // Match a 'print' as the first token\n    match(T_PRINT, \"print\");\n\n    // Parse the following expression and\n    // generate the assembly code\n    tree = binexpr(0);\n    reg = genAST(tree);\n    genprintint(reg);\n    genfreeregs();\n\n    // Match the following semicolon\n    // and stop if we are at EOF\n    semi();\n    if (Token.token == T_EOF)\n      return;\n  }\n}\n```\n\nIn each loop, the code finds a T_PRINT token. It then calls `binexpr()` to\nparse the expression. Finally, it finds the T_SEMI token. If a T_EOF token\nfollows, we break out of the loop.\n\nAfter each expression tree, the code in `gen.c` is called to convert\nthe tree into assembly code and to call the assembly `printint()` function\nto print out the final value.\n\n## Some Helper Functions\n\nThere are a couple of new helper functions in the above code, which I've put\ninto a new file, `misc.c`:\n\n```c\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    printf(\"%s expected on line %d\\n\", what, Line);\n    exit(1);\n  }\n}\n\n// Match a semicon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n```\n\nThese form part of the syntax checking in the parser. Later on, I'll add\nmore short functions to call `match()` to make our syntax checking easier.\n\n## Changes to `main()`\n\n`main()` used to call `binexpr()` directly to parse the single expression\nin the old input files. Now it does this:\n\n```c\n  scan(&Token);                 // Get the first token from the input\n  genpreamble();                // Output the preamble\n  statements();                 // Parse the statements in the input\n  genpostamble();               // Output the postamble\n  fclose(Outfile);              // Close the output file and exit\n  exit(0);\n```\n\n## Trying It Out\n\nThat's about it for the new and changed code. Let's give the new code\na whirl. Here is the new input file, `input01`:\n\n```\nprint 12 * 3;\nprint \n   18 - 2\n      * 4; print\n1 + 2 +\n  9 - 5/2 + 3*5;\n```\n\nYes I've decided to check that we have have tokens spread out across multiple\nlines. To compile and run the input file, do a `make test`:\n\n```make\n$ make test\ncc -o comp1 -g cg.c expr.c gen.c main.c misc.c scan.c stmt.c tree.c\n./comp1 input01\ncc -o out out.s\n./out\n36\n10\n25\n```\n\nAnd it works!\n\n## Conclusion and What's Next\n\nWe've added our first \"real\" statement grammar to our language. I've defined\nit in BNF notation, but it was easier to implement it with a loop and not\nrecursively. Don't worry, we'll go back to doing recursive parsing soon.\n\nAlong the way we had to modify the scanner, add support for keywords and\nidentifiers, and to more cleanly separate the generic code generator and\nthe CPU-specific generator.\n\nIn the next part of our compiler writing journey, we will add variables\nto the language. This will require a significant amount of work. [Next step](../06_Variables/Readme.md)\n"
  },
  {
    "path": "05_Statements/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers\n// and their names\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fprintf(stderr, \"Out of registers!\\n\");\n  exit(1);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0) {\n    fprintf(stderr, \"Error trying to free register %d\\n\", reg);\n    exit(1);\n  }\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\"\n\t\".LC0:\\n\"\n\t\"\\t.string\\t\\\"%d\\\\n\\\"\\n\"\n\t\"printint:\\n\"\n\t\"\\tpushq\\t%rbp\\n\"\n\t\"\\tmovq\\t%rsp, %rbp\\n\"\n\t\"\\tsubq\\t$16, %rsp\\n\"\n\t\"\\tmovl\\t%edi, -4(%rbp)\\n\"\n\t\"\\tmovl\\t-4(%rbp), %eax\\n\"\n\t\"\\tmovl\\t%eax, %esi\\n\"\n\t\"\\tleaq\t.LC0(%rip), %rdi\\n\"\n\t\"\\tmovl\t$0, %eax\\n\"\n\t\"\\tcall\tprintf@PLT\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"\\t.globl\\tmain\\n\"\n\t\"\\t.type\\tmain, @function\\n\"\n\t\"main:\\n\" \"\\tpushq\\t%rbp\\n\" \"\\tmovq\t%rsp, %rbp\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n  fputs(\"\\tmovl\t$0, %eax\\n\" \"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgload(int value) {\n\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n"
  },
  {
    "path": "05_Statements/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers\n// and their names\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r8\", \"r9\", \"r10\", \"r11\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fprintf(stderr, \"Out of registers!\\n\");\n  exit(1);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0) {\n    fprintf(stderr, \"Error trying to free register %d\\n\", reg);\n    exit(1);\n  }\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\tglobal\\tmain\\n\"\n\t\"\\textern\\tprintf\\n\"\n\t\"\\tsection\\t.text\\n\"\n\t\"LC0:\\tdb\\t\\\"%d\\\",10,0\\n\"\n\t\"printint:\\n\"\n\t\"\\tpush\\trbp\\n\"\n\t\"\\tmov\\trbp, rsp\\n\"\n\t\"\\tsub\\trsp, 16\\n\"\n\t\"\\tmov\\t[rbp-4], edi\\n\"\n\t\"\\tmov\\teax, [rbp-4]\\n\"\n\t\"\\tmov\\tesi, eax\\n\"\n\t\"\\tlea\trdi, [rel LC0]\\n\"\n\t\"\\tmov\teax, 0\\n\"\n\t\"\\tcall\tprintf\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"main:\\n\" \"\\tpush\\trbp\\n\" \"\\tmov\trbp, rsp\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n  fputs(\"\\tmov\teax, 0\\n\" \"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgload(int value) {\n\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n"
  },
  {
    "path": "05_Statements/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t\t// Current line number\nextern_ int Putback;\t\t\t// Character put back by scanner\nextern_ FILE *Infile;\t\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\n"
  },
  {
    "path": "05_Statements/decl.h",
    "content": "\n// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n// scan.c\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int intvalue);\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue);\n\n// gen.c\nint genAST(struct ASTnode *n);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nint cgload(int value);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nvoid cgprintint(int r);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nvoid statements(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\n"
  },
  {
    "path": "05_Statements/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n\n// Token types\nenum {\n  T_EOF, T_PLUS, T_MINUS, T_STAR, T_SLASH, T_INTLIT, T_SEMI, T_PRINT\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types\nenum {\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_INTLIT\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  struct ASTnode *left;\t\t// Left and right child trees\n  struct ASTnode *right;\n  int intvalue;\t\t\t// For A_INTLIT, the integer value\n};\n"
  },
  {
    "path": "05_Statements/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n\n  // For an INTLIT token, make a leaf AST node for it\n  // and scan in the next token. Otherwise, a syntax error\n  // for any other token type.\n  switch (Token.token) {\n    case T_INTLIT:\n      n = mkastleaf(A_INTLIT, Token.intvalue);\n      scan(&Token);\n      return (n);\n    default:\n      fprintf(stderr, \"syntax error on line %d, token %d\\n\", Line,\n\t      Token.token);\n      exit(1);\n  }\n}\n\n\n// Convert a binary operator token into an AST operation.\nstatic int arithop(int tokentype) {\n  switch (tokentype) {\n    case T_PLUS:\n      return (A_ADD);\n    case T_MINUS:\n      return (A_SUBTRACT);\n    case T_STAR:\n      return (A_MULTIPLY);\n    case T_SLASH:\n      return (A_DIVIDE);\n    default:\n      fprintf(stderr, \"syntax error on line %d, token %d\\n\", Line, tokentype);\n      exit(1);\n  }\n}\n\n// Operator precedence for each token\nstatic int OpPrec[] = { 0, 10, 10, 20, 20, 0 };\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0) {\n    fprintf(stderr, \"syntax error on line %d, token %d\\n\", Line, tokentype);\n    exit(1);\n  }\n  return (prec);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the integer literal on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If we hit a semicolon, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "05_Statements/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given an AST, generate\n// assembly code recursively\nint genAST(struct ASTnode *n) {\n  int leftreg, rightreg;\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left);\n  if (n->right)\n    rightreg = genAST(n->right);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_INTLIT:\n      return (cgload(n->intvalue));\n    default:\n      fprintf(stderr, \"Unknown AST operator %d\\n\", n->op);\n      exit(1);\n  }\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\n"
  },
  {
    "path": "05_Statements/input01",
    "content": "print 12 * 3;\nprint \n   18 - 2\n      * 4; print\n1 + 2 +\n  9 - 5/2 + 3*5;\n"
  },
  {
    "path": "05_Statements/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nvoid main(int argc, char *argv[]) {\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  statements();\t\t\t// Parse the statements in the input\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  exit(0);\n}\n"
  },
  {
    "path": "05_Statements/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    printf(\"%s expected on line %d\\n\", what, Line);\n    exit(1);\n  }\n}\n\n// Match a semicon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n"
  },
  {
    "path": "05_Statements/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      printf(\"identifier too long on line %d\\n\", Line);\n      exit(1);\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'p':\n      if (!strcmp(s, \"print\"))\n\treturn (T_PRINT);\n      break;\n  }\n  return (0);\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif (tokentype = keyword(Text)) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so an error for now\n\tprintf(\"Unrecognised symbol %s on line %d\\n\", Text, Line);\n\texit(1);\n      }\n      // The character isn't part of any recognised token, error\n      printf(\"Unrecognised character %c on line %d\\n\", c, Line);\n      exit(1);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "05_Statements/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// statements: statement\n//      | statement statements\n//      ;\n//\n// statement: 'print' expression ';'\n//      ;\n\n\n// Parse one or more statements\nvoid statements(void) {\n  struct ASTnode *tree;\n  int reg;\n\n  while (1) {\n    // Match a 'print' as the first token\n    match(T_PRINT, \"print\");\n\n    // Parse the following expression and\n    // generate the assembly code\n    tree = binexpr(0);\n    reg = genAST(tree);\n    genprintint(reg);\n    genfreeregs();\n\n    // Match the following semicolon\n    // and stop if we are at EOF\n    semi();\n    if (Token.token == T_EOF)\n      return;\n  }\n}\n"
  },
  {
    "path": "05_Statements/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL) {\n    fprintf(stderr, \"Unable to malloc in mkastnode()\\n\");\n    exit(1);\n  }\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->left = left;\n  n->right = right;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int intvalue) {\n  return (mkastnode(op, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue) {\n  return (mkastnode(op, left, NULL, intvalue));\n}\n"
  },
  {
    "path": "06_Variables/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g $(SRCN)\n\nclean:\n\trm -f comp1 compn *.o *.s out\n\ntest: comp1 input01 input02\n\t./comp1 input01\n\tcc -o out out.s\n\t./out\n\t./comp1 input02\n\tcc -o out out.s\n\t./out\n\ntestn: compn input01 input02\n\t./compn input01\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out out.o\n\t./out\n\t./compn input02\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out out.o\n\t./out\n"
  },
  {
    "path": "06_Variables/Readme.md",
    "content": "# Part 6: Variables\n\nI've just finished adding global variables to the compiler and, as I\nsuspected, it was a lot of work. Also, pretty much every file in the\ncompiler got modified in the process. So this part of the journey is\ngoing to be long.\n\n## What Do We Want from Variables?\n\nWe want to be able to:\n\n + Declare variables\n + Use variables to get stored values\n + Assign to variables\n\nHere is `input02` which will be our test program:\n\n```\nint fred;\nint jim;\nfred= 5;\njim= 12;\nprint fred + jim;\n```\n\nThe most obvious change is that the grammar now has\nvariable declarations, assignment statements and variables names in\nexpressions. However, before we get to that, let's look at how we\nimplement variables.\n\n## The Symbol Table\n\nEvery compiler is going to need a\n[symbol table](https://en.wikipedia.org/wiki/Symbol_table). Later on,\nwe will hold more than just global variables. But for now, here is\nthe structure of an entry in the table (from `defs.h`):\n\n```c\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n};\n```\n\nWe have an array of symbols in `data.h`:\n\n```c\n#define NSYMBOLS        1024            // Number of symbol table entries\nextern_ struct symtable Gsym[NSYMBOLS]; // Global symbol table\nstatic int Globs = 0;                   // Position of next free global symbol slot\n```\n\n`Globs` is actually in `sym.c`, the file that manages the symbol table.\nIn here we have these management functions:\n\n  + `int findglob(char *s)`: Determine if the symbol s is in the global\n     symbol table. Return its slot position or -1 if not found.\n  + `static int newglob(void)`: Get the position of a new global symbol\n     slot, or die if we've run out of positions.\n  + `int addglob(char *name)`: Add a global symbol to the symbol table.\n     Return the slot number in the symbol table.\n\nThe code is fairly straight forward, so I won't bother to give the code\nhere in the discussion. With these functions, we can find symbols and\nadd new symbols to the symbol table.\n\n## Scanning and New Tokens\n\nIf you look at the example input file, we need a few new tokens:\n\n  + 'int', known as T_INT\n  + '=', known as T_EQUALS\n  + identifier names, known as T_IDENT\n\nThe scanning of '=' is easy to add to `scan()`:\n\n```c\n  case '=':\n    t->token = T_EQUALS; break;\n```\n\nWe can add the 'int' keyword to `keyword()`:\n\n```c\n  case 'i':\n    if (!strcmp(s, \"int\"))\n      return (T_INT);\n    break;\n```\n\nFor identifiers, we are already using `scanident()` to store words into the\n`Text` variable. Instead of dying if a word is not a keyword, we can\nreturn a T_IDENT token:\n\n```c\n   if (isalpha(c) || '_' == c) {\n      // Read in a keyword or identifier\n      scanident(c, Text, TEXTLEN);\n\n      // If it's a recognised keyword, return that token\n      if (tokentype = keyword(Text)) {\n        t->token = tokentype;\n        break;\n      }\n      // Not a recognised keyword, so it must be an identifier\n      t->token = T_IDENT;\n      break;\n    }\n```\n\n## The New Grammar\n\nWe're about ready to look at the changes to the grammar of our input\nlanguage. As before, I'll define it with BNF notation:\n\n```\n statements: statement\n      |      statement statements\n      ;\n\n statement: 'print' expression ';'\n      |     'int'   identifier ';'\n      |     identifier '=' expression ';'\n      ;\n\n identifier: T_IDENT\n      ;\n```\n\nAn identifier is returned as a T_IDENT token, and we already have the code\nto parse print statements. But, as we now have three types of statements,\nit makes sense to write a  function to deal with each one. Our top-level\n`statements()` function in `stmt.c` now looks like:\n\n```c\n// Parse one or more statements\nvoid statements(void) {\n\n  while (1) {\n    switch (Token.token) {\n    case T_PRINT:\n      print_statement();\n      break;\n    case T_INT:\n      var_declaration();\n      break;\n    case T_IDENT:\n      assignment_statement();\n      break;\n    case T_EOF:\n      return;\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n    }\n  }\n}\n```\n\nI've moved the old print statement code into `print_statement()` and\nyou can browse that yourself.\n\n## Variable Declarations\n\nLet's look at variable declarations. This\nis in a new file, `decl.c`, as we are going to have lots of other types\nof declarations in the future.\n\n```c\n// Parse the declaration of a variable\nvoid var_declaration(void) {\n\n  // Ensure we have an 'int' token followed by an identifier\n  // and a semicolon. Text now has the identifier's name.\n  // Add it as a known identifier\n  match(T_INT, \"int\");\n  ident();\n  addglob(Text);\n  genglobsym(Text);\n  semi();\n}\n```\n\nThe `ident()` and `semi()` functions are wrappers around `match()`:\n\n```c\nvoid semi(void)  { match(T_SEMI, \";\"); }\nvoid ident(void) { match(T_IDENT, \"identifier\"); }\n```\n\nBack to `var_declaration()`, once we have scanned in the idenfiier into\nthe `Text` buffer, we can add this to the global symbol table with\n`addglob(Text)`. The code in there allows a variable to be declared\nmultiple times (for now).\n\n## Assignment Statements\n\nHere's the code for `assignment_statement()` in `stmt.c`:\n\n```c\nvoid assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // Check it's been defined then make a leaf node for it\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared variable\", Text);\n  }\n  right = mkastleaf(A_LVIDENT, id);\n\n  // Ensure we have an equals sign\n  match(T_EQUALS, \"=\");\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Make an assignment AST tree\n  tree = mkastnode(A_ASSIGN, left, right, 0);\n\n  // Generate the assembly code for the assignment\n  genAST(tree, -1);\n  genfreeregs();\n\n  // Match the following semicolon\n  semi();\n}\n```\n\nWe have a couple of new AST node types. A_ASSIGN takes the expression in\nthe left-hand child and assigns it to the right-hand child. And the\nright-hand child will be an A_LVIDENT node.\n\nWhy did I call this node *A_LVIDENT*? Because it represents an *lvalue*\nidentifier. So what's an\n[lvalue](https://en.wikipedia.org/wiki/Value_(computer_science)#lrvalue)?\n\nAn lvalue is a value that is tied to a specific location. Here, it's the\naddress in memory which holds a variable's value. When we do:\n\n```\n   area = width * height;\n```\n\nwe *assign* the result of the right-hand side (i.e. the *rvalue*) to the\nvariable in the left-hand side (i.e. the *lvalue*). The *rvalue* isn't tied\nto a specific location. Here, the expression result is probably in some\narbitrary register.\n\nAlso note that, although the assignment statement has the syntax\n\n```\n  identifier '=' expression ';'\n```\n\nwe will make the expression the left sub-tree of the A_ASSIGN node\nand save the A_LVIDENT details in the right sub-tree. Why? Because\nwe need to evaluate the expression *before* we save it into the variable.\n\n## Changes to the AST Structure\n\nWe now need to store either an integer literal value in A_INTLIT AST nodes, or\nthe details of the symbol for A_IDENT AST nodes. I've added a *union* to the\nAST structure to do this (in `defs.h`):\n\n```c\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  struct ASTnode *left;         // Left and right child trees\n  struct ASTnode *right;\n  union {\n    int intvalue;               // For A_INTLIT, the integer value\n    int id;                     // For A_IDENT, the symbol slot number\n  } v;\n};\n```\n\n## Generating the Assignment Code\n\nLet's now look at the changes to `genAST()` in `gen.c`\n\n```c\nint genAST(struct ASTnode *n, int reg) {\n  int leftreg, rightreg;\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, -1);\n  if (n->right)\n    rightreg = genAST(n->right, leftreg);\n\n  switch (n->op) {\n  ...\n    case A_INTLIT:\n    return (cgloadint(n->v.intvalue));\n  case A_IDENT:\n    return (cgloadglob(Gsym[n->v.id].name));\n  case A_LVIDENT:\n    return (cgstorglob(reg, Gsym[n->v.id].name));\n  case A_ASSIGN:\n    // The work has already been done, return the result\n    return (rightreg);\n  default:\n    fatald(\"Unknown AST operator\", n->op);\n  }\n\n```\n\nNote that we evaluate the left-hand AST child first, and we get back\na register number that holds the left-hand sub-tree's value. We now\npass this register number to the right-hand sub-tree. We need to do\nthis for A_LVIDENT nodes, so that the `cgstorglob()` function in `cg.c`\nknows which register holds the rvalue result of the assignment expression.\n\nSo, consider this AST tree:\n\n```\n           A_ASSIGN\n          /        \\\n     A_INTLIT   A_LVIDENT\n        (3)        (5)\n```\n\nWe call `leftreg = genAST(n->left, -1);` to evaluate the A_INTLIT operation.\nThis will `return (cgloadint(n->v.intvalue));`, i.e. load a register with the\nvalue 3 and return the register id.\n\nThen, we call `rightreg = genAST(n->right, leftreg);` to evaluate the\nA_LVIDENT operation. This will\n`return (cgstorglob(reg, Gsym[n->v.id].name));`, i.e. store the\nregister into the variable whose name is in `Gsym[5]`.\n\nThen we switch to the A_ASSIGN case. Well, all our work has already been done.\nThe rvalue is still in a register, so let's leave it there and return it.\nLater, we'll be able to do expressions like:\n\n```\n  a= b= c = 0;\n```\n\nwhere an assignment is not just a statement but also an expression.\n\n## Generating x86-64 Code\n\nYou would have noticed that I changed the name of the old `cgload()`\nfunction to `cgloadint()`. This is more specific. We now have a\nfunction to load the value out of a global variable (in `cg.c`):\n\n```c\nint cgloadglob(char *identifier) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", identifier, reglist[r]);\n  return (r);\n}\n```\n\nSimilarly, we need a function to save a register into a variable:\n\n```c\n// Store a register's value into a variable\nint cgstorglob(int r, char *identifier) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], identifier);\n  return (r);\n}\n```\n\nWe also need a function to create a new global integer variable:\n\n```c\n// Generate a global symbol\nvoid cgglobsym(char *sym) {\n  fprintf(Outfile, \"\\t.comm\\t%s,8,8\\n\", sym);\n}\n```\n\nOf course, we can't let the parser access this code directly. Instead,\nthere is a function in the generic code generator in `gen.c` \nthat acts as the interface:\n\n```c\nvoid genglobsym(char *s) { cgglobsym(s); }\n```\n\n## Variables in Expressions\n\nSo now we can assign to variables. But how do we get a variable's value into\nan expression. Well, we already have a `primary()` function to get an\ninteger literal. Let's modify it to also load a variable's value:\n\n```c\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    n = mkastleaf(A_INTLIT, Token.intvalue);\n    break;\n\n  case T_IDENT:\n    // Check that this identifier exists\n    id = findglob(Text);\n    if (id == -1)\n      fatals(\"Unknown variable\", Text);\n\n    // Make a leaf AST node for it\n    n = mkastleaf(A_IDENT, id);\n    break;\n\n  default:\n    fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n```\n\nNote the syntax checking in the T_IDENT case to ensure the variable has\nbeen declared before we try to use it.\n\nAlso note that the AST leaf node that *retrieves* a variable's value is\nan A_IDENT node. The leaf that saves into a variable is an A_LVIDENT node.\nThis is the difference between *rvalues* and *lvalues*.\n\n## Trying It Out\n\nI think that's about it for variable declarations, so let's try it out\nwith the `input02` file:\n\n```\nint fred;\nint jim;\nfred= 5;\njim= 12;\nprint fred + jim;\n```\n\nWe can `make test` to do this:\n\n```\n$ make test\ncc -o comp1 -g cg.c decl.c expr.c gen.c main.c misc.c scan.c\n               stmt.c sym.c tree.c\n...\n./comp1 input02\ncc -o out out.s\n./out\n17\n```\n\nAs you can see, we calculated `fred + jim` which is 5 + 12 or 17.\nHere are the new assembly lines in `out.s`:\n\n```\n        .comm   fred,8,8                # Declare fred\n        .comm   jim,8,8                 # Declare jim\n        ...\n        movq    $5, %r8\n        movq    %r8, fred(%rip)         # fred = 5\n        movq    $12, %r8\n        movq    %r8, jim(%rip)          # jim = 12\n        movq    fred(%rip), %r8\n        movq    jim(%rip), %r9\n        addq    %r8, %r9                # fred + jim\n```\n\n## Other Changes\n\nI've probably made a few other changes. The only main one that I can\nremember is to create some helper functions in `misc.c` to make it\neasier to report fatal errors:\n\n```c\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line); exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line); exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line); exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line); exit(1);\n}\n```\n\n## Conclusion and What's Next\n\nSo that was a lot of work. We had to write the beginnings of symbol\ntable management. We had to deal with two new statement types. We\nhad to add some new tokens and some new AST node types. Finally, we\nhad to add some code to generate the correct x86-64 assembly output.\n\nTry writing a few example input files and see if the compiler works\nas it should, especially if it detects syntax errors and semantic\nerrors (variable use without a declaration).\n\nIn the next part of our compiler writing journey, we will\nadd the six comparison operators to our language. That will\nallow us to start on the control structures in the part after that. [Next step](../07_Comparisons/Readme.md)\n"
  },
  {
    "path": "06_Variables/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\"\n\t\".LC0:\\n\"\n\t\"\\t.string\\t\\\"%d\\\\n\\\"\\n\"\n\t\"printint:\\n\"\n\t\"\\tpushq\\t%rbp\\n\"\n\t\"\\tmovq\\t%rsp, %rbp\\n\"\n\t\"\\tsubq\\t$16, %rsp\\n\"\n\t\"\\tmovl\\t%edi, -4(%rbp)\\n\"\n\t\"\\tmovl\\t-4(%rbp), %eax\\n\"\n\t\"\\tmovl\\t%eax, %esi\\n\"\n\t\"\\tleaq\t.LC0(%rip), %rdi\\n\"\n\t\"\\tmovl\t$0, %eax\\n\"\n\t\"\\tcall\tprintf@PLT\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"\\t.globl\\tmain\\n\"\n\t\"\\t.type\\tmain, @function\\n\"\n\t\"main:\\n\" \"\\tpushq\\t%rbp\\n\" \"\\tmovq\t%rsp, %rbp\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n  fputs(\"\\tmovl\t$0, %eax\\n\" \"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgloadint(int value) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(char *identifier) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", identifier, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, char *identifier) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], identifier);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(char *sym) {\n  fprintf(Outfile, \"\\t.comm\\t%s,8,8\\n\", sym);\n}\n"
  },
  {
    "path": "06_Variables/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r8\", \"r9\", \"r10\", \"r11\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\tglobal\\tmain\\n\"\n\t\"\\textern\\tprintf\\n\"\n\t\"\\tsection\\t.text\\n\"\n\t\"LC0:\\tdb\\t\\\"%d\\\",10,0\\n\"\n\t\"printint:\\n\"\n\t\"\\tpush\\trbp\\n\"\n\t\"\\tmov\\trbp, rsp\\n\"\n\t\"\\tsub\\trsp, 16\\n\"\n\t\"\\tmov\\t[rbp-4], edi\\n\"\n\t\"\\tmov\\teax, [rbp-4]\\n\"\n\t\"\\tmov\\tesi, eax\\n\"\n\t\"\\tlea\trdi, [rel LC0]\\n\"\n\t\"\\tmov\teax, 0\\n\"\n\t\"\\tcall\tprintf\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"main:\\n\" \"\\tpush\\trbp\\n\" \"\\tmov\trbp, rsp\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n  fputs(\"\\tmov\teax, 0\\n\" \"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgloadint(int value) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(char *identifier) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], identifier);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, char *identifier) {\n  fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", identifier, reglist[r]);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(char *sym) {\n  fprintf(Outfile, \"\\tcommon\\t%s 8:8\\n\", sym);\n}\n"
  },
  {
    "path": "06_Variables/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t\t// Current line number\nextern_ int Putback;\t\t\t// Character put back by scanner\nextern_ FILE *Infile;\t\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n"
  },
  {
    "path": "06_Variables/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the declaration of a variable\nvoid var_declaration(void) {\n\n  // Ensure we have an 'int' token followed by an identifier\n  // and a semicolon. Text now has the identifier's name.\n  // Add it as a known identifier\n  match(T_INT, \"int\");\n  ident();\n  addglob(Text);\n  genglobsym(Text);\n  semi();\n}\n"
  },
  {
    "path": "06_Variables/decl.h",
    "content": "\n// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n// scan.c\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int intvalue);\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue);\n\n// gen.c\nint genAST(struct ASTnode *n, int reg);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\nvoid genglobsym(char *s);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nint cgloadint(int value);\nint cgloadglob(char *identifier);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nvoid cgprintint(int r);\nint cgstorglob(int r, char *identifier);\nvoid cgglobsym(char *sym);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nvoid statements(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name);\n\n// decl.c\nvoid var_declaration(void);\n"
  },
  {
    "path": "06_Variables/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF, T_PLUS, T_MINUS, T_STAR, T_SLASH, T_INTLIT, T_SEMI, T_EQUALS,\n  T_IDENT,\n  // Keywords\n  T_PRINT, T_INT\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types\nenum {\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_INTLIT,\n  A_IDENT, A_LVIDENT, A_ASSIGN\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  struct ASTnode *left;\t\t// Left and right child trees\n  struct ASTnode *right;\n  union {\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int id;\t\t\t// For A_IDENT, the symbol slot number\n  } v;\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n};\n"
  },
  {
    "path": "06_Variables/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    n = mkastleaf(A_INTLIT, Token.intvalue);\n    break;\n\n  case T_IDENT:\n    // Check that this identifier exists\n    id = findglob(Text);\n    if (id == -1)\n      fatals(\"Unknown variable\", Text);\n\n    // Make a leaf AST node for it\n    n = mkastleaf(A_IDENT, id);\n    break;\n\n  default:\n    fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into an AST operation.\nstatic int arithop(int tokentype) {\n  switch (tokentype) {\n  case T_PLUS:\n    return (A_ADD);\n  case T_MINUS:\n    return (A_SUBTRACT);\n  case T_STAR:\n    return (A_MULTIPLY);\n  case T_SLASH:\n    return (A_DIVIDE);\n  default:\n    fatald(\"Syntax error, token\", tokentype);\n  }\n}\n\n// Operator precedence for each token\nstatic int OpPrec[] = { 0, 10, 10, 20, 20, 0 };\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the primary tree on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If we hit a semicolon, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "06_Variables/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given an AST, generate assembly code recursively.\n// Return the register id with the tree's final value\nint genAST(struct ASTnode *n, int reg) {\n  int leftreg, rightreg;\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, -1);\n  if (n->right)\n    rightreg = genAST(n->right, leftreg);\n\n  switch (n->op) {\n  case A_ADD:\n    return (cgadd(leftreg, rightreg));\n  case A_SUBTRACT:\n    return (cgsub(leftreg, rightreg));\n  case A_MULTIPLY:\n    return (cgmul(leftreg, rightreg));\n  case A_DIVIDE:\n    return (cgdiv(leftreg, rightreg));\n  case A_INTLIT:\n    return (cgloadint(n->v.intvalue));\n  case A_IDENT:\n    return (cgloadglob(Gsym[n->v.id].name));\n  case A_LVIDENT:\n    return (cgstorglob(reg, Gsym[n->v.id].name));\n  case A_ASSIGN:\n    // The work has already been done, return the result\n    return (rightreg);\n  default:\n    fatald(\"Unknown AST operator\", n->op);\n  }\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\n\nvoid genglobsym(char *s) {\n  cgglobsym(s);\n}\n"
  },
  {
    "path": "06_Variables/input01",
    "content": "print 12 * 3;\nprint \n   18 - 2\n      * 4; print\n1 + 2 +\n  9 - 5/2 + 3*5;\n"
  },
  {
    "path": "06_Variables/input02",
    "content": "int fred;\nint jim;\nfred= 5;\njim= 12;\nprint fred + jim;\n"
  },
  {
    "path": "06_Variables/input03",
    "content": "int x;\nx= 1;     print x;\nx= x + 1; print x;\nx= x + 1; print x;\nx= x + 1; print x;\nx= x + 1; print x;\n"
  },
  {
    "path": "06_Variables/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nvoid main(int argc, char *argv[]) {\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  statements();\t\t\t// Parse the statements in the input\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  exit(0);\n}\n"
  },
  {
    "path": "06_Variables/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line); exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line); exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line); exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line); exit(1);\n}\n"
  },
  {
    "path": "06_Variables/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n  case 'i':\n    if (!strcmp(s, \"int\"))\n      return (T_INT);\n    break;\n  case 'p':\n    if (!strcmp(s, \"print\"))\n      return (T_PRINT);\n    break;\n  }\n  return (0);\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n  case EOF:\n    t->token = T_EOF;\n    return (0);\n  case '+':\n    t->token = T_PLUS;\n    break;\n  case '-':\n    t->token = T_MINUS;\n    break;\n  case '*':\n    t->token = T_STAR;\n    break;\n  case '/':\n    t->token = T_SLASH;\n    break;\n  case ';':\n    t->token = T_SEMI;\n    break;\n  case '=':\n    t->token = T_EQUALS;\n    break;\n  default:\n\n    // If it's a digit, scan the\n    // literal integer value in\n    if (isdigit(c)) {\n      t->intvalue = scanint(c);\n      t->token = T_INTLIT;\n      break;\n    } else if (isalpha(c) || '_' == c) {\n      // Read in a keyword or identifier\n      scanident(c, Text, TEXTLEN);\n\n      // If it's a recognised keyword, return that token\n      if (tokentype = keyword(Text)) {\n\tt->token = tokentype;\n\tbreak;\n      }\n      // Not a recognised keyword, so it must be an identifier\n      t->token = T_IDENT;\n      break;\n    }\n    // The character isn't part of any recognised token, error\n    fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "06_Variables/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// statements: statement\n//      |      statement statements\n//      ;\n//\n// statement: 'print' expression ';'\n//      |     'int'   identifier ';'\n//      |     identifier '=' expression ';'\n//      ;\n//\n// identifier: T_IDENT\n//      ;\n\nvoid print_statement(void) {\n  struct ASTnode *tree;\n  int reg;\n\n  // Match a 'print' as the first token\n  match(T_PRINT, \"print\");\n\n  // Parse the following expression and\n  // generate the assembly code\n  tree = binexpr(0);\n  reg = genAST(tree, -1);\n  genprintint(reg);\n  genfreeregs();\n\n  // Match the following semicolon\n  semi();\n}\n\nvoid assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // Check it's been defined then make a leaf node for it\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared variable\", Text);\n  }\n  right = mkastleaf(A_LVIDENT, id);\n\n  // Ensure we have an equals sign\n  match(T_EQUALS, \"=\");\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Make an assignment AST tree\n  tree = mkastnode(A_ASSIGN, left, right, 0);\n\n  // Generate the assembly code for the assignment\n  genAST(tree, -1);\n  genfreeregs();\n\n  // Match the following semicolon\n  semi();\n}\n\n\n// Parse one or more statements\nvoid statements(void) {\n\n  while (1) {\n    switch (Token.token) {\n    case T_PRINT:\n      print_statement();\n      break;\n    case T_INT:\n      var_declaration();\n      break;\n    case T_IDENT:\n      assignment_statement();\n      break;\n    case T_EOF:\n      return;\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n    }\n  }\n}\n"
  },
  {
    "path": "06_Variables/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic int Globs = 0;\t\t// Position of next free global symbol slot\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table.\n// Return the slot number in the symbol table\nint addglob(char *name) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  return (y);\n}\n"
  },
  {
    "path": "06_Variables/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->left = left;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int intvalue) {\n  return (mkastnode(op, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue) {\n  return (mkastnode(op, left, NULL, intvalue));\n}\n"
  },
  {
    "path": "07_Comparisons/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g $(SRCN)\n\nclean:\n\trm -f comp1 compn *.o *.s out\n\ntest: comp1 input04\n\t./comp1 input04\n\tcc -o out out.s\n\t./out\n\ntestn: compn input04\n\t./compn input04\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out out.o\n\t./out\n"
  },
  {
    "path": "07_Comparisons/Readme.md",
    "content": "# Part 7: Comparison Operators\n\nI was going to add IF statements next, but then I realised that I'd\nbetter add some comparison operators first. This turned out to be quite\neasy, because they are binary operators like the existing ones.\n\nSo let's quickly see what the changes are to add the six comparison\noperators: `==`, `!=`, `<`, `>`, `<=` and `>=`.\n\n## Adding New Tokens\n\nWe will have six new tokens, so let's add them to `defs.h`:\n\n```c\n// Token types\nenum {\n  T_EOF,\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_INTLIT, T_SEMI, T_ASSIGN, T_IDENT,\n  // Keywords\n  T_PRINT, T_INT\n};\n```\n\nI've rearranged the tokens so that the ones with precedence come, in\nlow-to-high precedence order, before the tokens that don't have any\nprecedence.\n\n## Scanning The Tokens\n\nNow we have to scan them in. Note that we have to distinguish between\n`=` and `==`, `<` and `<=`, `>` and `>=`. So we will need to read in\nan extra character from the input and put it back if we don't need it.\nHere's the new code in `scan()` from `scan.c`:\n\n```c\n  case '=':\n    if ((c = next()) == '=') {\n      t->token = T_EQ;\n    } else {\n      putback(c);\n      t->token = T_ASSIGN;\n    }\n    break;\n  case '!':\n    if ((c = next()) == '=') {\n      t->token = T_NE;\n    } else {\n      fatalc(\"Unrecognised character\", c);\n    }\n    break;\n  case '<':\n    if ((c = next()) == '=') {\n      t->token = T_LE;\n    } else {\n      putback(c);\n      t->token = T_LT;\n    }\n    break;\n  case '>':\n    if ((c = next()) == '=') {\n      t->token = T_GE;\n    } else {\n      putback(c);\n      t->token = T_GT;\n    }\n    break;\n```\n\nI also changed the name of the `=` token to T_ASSIGN to ensure I didn't get\nconfused between it and the new T_EQ token.\n\n## New Expression Code\n\nWe can now scan in the six new tokens. So now we have to parse them when\nthey appear in expressions, and also enforce their operator precedence.\n\nBy now you would have worked out that:\n\n  + I'm building what will become a self-compiling compiler\n  + in the C language\n  + using the SubC compiler as a reference.\n\nThe implication is that I'm writing a compiler for enough of a subset of\nC (just as SubC) so that it will compile itself. Therefore, I should use\nthe normal\n[C operator precedence order](https://en.cppreference.com/w/c/language/operator_precedence). This means that the comparison operators have lower precedence\nthan multiply and divide.\n\nI also realised that the switch statement I was using to map tokens to AST\nnode types was only going to get bigger. So I decided to rearrange the\nAST node types so that there is a 1:1 mapping between them for all the\nbinary operators (in `defs.h`):\n\n```c\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ADD=1, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT,\n  A_IDENT, A_LVIDENT, A_ASSIGN\n};\n```\n\nNow in `expr.c`, I can simplify the token to AST node conversion and also\nadd in the new tokens' precedence:\n\n```c\n// Convert a binary operator token into an AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int arithop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return(tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,                    // T_EOF, T_PLUS, T_MINUS\n  20, 20,                       // T_STAR, T_SLASH\n  30, 30,                       // T_EQ, T_NE\n  40, 40, 40, 40                // T_LT, T_GT, T_LE, T_GE\n};\n```\n\nThat's it for the parsing and operator precedence!\n\n## Code Generation\n\nAs the six new operators are binary operators, it's easy to modify the\ngeneric code generator in `gen.c` to deal with them:\n\n```c\n  case A_EQ:\n    return (cgequal(leftreg, rightreg));\n  case A_NE:\n    return (cgnotequal(leftreg, rightreg));\n  case A_LT:\n    return (cglessthan(leftreg, rightreg));\n  case A_GT:\n    return (cggreaterthan(leftreg, rightreg));\n  case A_LE:\n    return (cglessequal(leftreg, rightreg));\n  case A_GE:\n    return (cggreaterequal(leftreg, rightreg));\n```\n\n## x86-64 Code Generation\n\nNow it gets a bit tricky. In C, the comparison operators return a value.\nIf they evaluate true, their result is 1. If they evaluate false, their\nresult is 0. We need to write x86-64 assembly code to reflect this.\n\nLuckily there are some x86-64 instructions to do this. Unfortunately,\nthere are some issues to deal with along the way. Consider this\nx86-64 instruction:\n\n```\n    cmpq %r8,%r9\n```\n\nThe above `cmpq` instruction performs %r9 - %r8 and sets several status\nflags including the negative and zero flags. Thus, we can look at the\nflag combinations to see the result of the comparisons:\n\n| Comparison | Operation | Flags If True |\n|------------|-----------|---------------|\n| %r8 == %r9 | %r9 - %r8 |  Zero         |\n| %r8 != %r9 | %r9 - %r8 |  Not Zero     |\n| %r8 > %r9  | %r9 - %r8 |  Not Zero, Negative |\n| %r8 < %r9  | %r9 - %r8 |  Not Zero, Not Negative |\n| %r8 >= %r9 | %r9 - %r8 |  Zero or Negative |\n| %r8 <= %r9 | %r9 - %r8 |  Zero or Not Negative |\n\nThere are six x86-64 instructions which set a register to 1 or 0 based on\nthe two flag values: `sete`, `setne`, `setg`, `setl`, `setge`\nand `setle` in the order of the above table rows.\n\nThe problem is, these instructions only set the lowest byte of a register.\nIf the register already has bits set outside of the lowest byte, they will\nstay set. So we might set a variable to 1, but if it already has the value\n1000 (decimal), then it will now be 1001 which is not what we want.\n\nThe solution is to `andq` the register after the `setX` instruction to\nget rid of the unwanted bits. In `cg.c` there is a general comparison\nfunction to do this:\n\n```c\n// Compare two registers.\nstatic int cgcompare(int r1, int r2, char *how) {\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", how, breglist[r2]);\n  fprintf(Outfile, \"\\tandq\\t$255,%s\\n\", reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n```\n\nwhere `how` is one of the `setX` instructions. Note that we perform\n\n```\n   cmpq reglist[r2], reglist[r1]\n```\n\nbecause this is actually `reglist[r1] - reglist[r2]` which is what we really\nwant.\n\n## x86-64 Registers\n\nWe need to take a short diversion here to discuss the registers in the\nx86-64 architecture. x86-64 has several 64-bit general purpose registers,\nbut we can also use different register names to access and work on\nsubsections of these registers.\n\n![](https://i.stack.imgur.com/N0KnG.png)\n\nThe above image from *stack.imgur.com* shows that, for the 64-bit *r8* register,\nwe can access the low 32 bits of this register by using the \"*r8d*\" register.\nSimilarly, the \"*r8w*\" register is the low 16 bits and the \"*r8b*\" register\nis the low 8 bits of the *r8* register.\n\nIn the `cgcompare()` function, the code uses the `reglist[]` array to\ncompare the two 64-bit registers, but then sets a flag in the 8-bit\nversion of the second register by using the names in the `breglist[]` array.\nThe x86-64 architecture only allows the `setX` instructions to operate on\nthe 8-bit register names, thus the need for the `breglist[]` array.\n\n## Creating Several Compare Instructions\n\nNow that we have this general function, we can write the six actual\ncomparison functions:\n\n```c\nint cgequal(int r1, int r2) { return(cgcompare(r1, r2, \"sete\")); }\nint cgnotequal(int r1, int r2) { return(cgcompare(r1, r2, \"setne\")); }\nint cglessthan(int r1, int r2) { return(cgcompare(r1, r2, \"setl\")); }\nint cggreaterthan(int r1, int r2) { return(cgcompare(r1, r2, \"setg\")); }\nint cglessequal(int r1, int r2) { return(cgcompare(r1, r2, \"setle\")); }\nint cggreaterequal(int r1, int r2) { return(cgcompare(r1, r2, \"setge\")); }\n```\n\nAs with the other binary operator functions, one register is freed and\nthe other register returns with the result.\n\n# Putting It Into Action\n\nHave a look at the `input04` input file:\n\n```c\nint x;\nx= 7 < 9;  print x;\nx= 7 <= 9; print x;\nx= 7 != 9; print x;\nx= 7 == 7; print x;\nx= 7 >= 7; print x;\nx= 7 <= 7; print x;\nx= 9 > 7;  print x;\nx= 9 >= 7; print x;\nx= 9 != 7; print x;\n```\n\nAll of these comparisons are true, so we should print nine 1s out. Do\na `make test` to confirm this.\n\nLet's look at the assembly code output by the first comparison:\n\n```\n        movq    $7, %r8\n        movq    $9, %r9\n        cmpq    %r9, %r8        # Perform %r8 - %r9, i.e. 7 - 9\n        setl    %r9b            # Set %r9b to 1 if 7 is less than 9\n        andq    $255,%r9        # Remove all other bits in %r9\n        movq    %r9, x(%rip)    # Save the result in x\n        movq    x(%rip), %r8\n        movq    %r8, %rdi\n        call    printint        # Print x out\n```\n\nYes there is some inefficient assembly code above. We haven't even started\nto worry about optimised code yet. To quote Donald Knuth:\n\n> **Premature optimization is the root of all evil (or at least most of it)\n  in programming.**\n\n## Conclusion and What's Next\n\nThat was a nice and easy addition to the compiler. The next part of the\njourney will be much more complicated.\n\nIn the next part of our compiler writing journey, we will add IF statements\nto the compiler and make use of the comparison operators that we just added. [Next step](../08_If_Statements/Readme.md)\n"
  },
  {
    "path": "07_Comparisons/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\n// We need a list of byte registers, too\nstatic int freereg[4];\nstatic char  *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\"\n\t\".LC0:\\n\"\n\t\"\\t.string\\t\\\"%d\\\\n\\\"\\n\"\n\t\"printint:\\n\"\n\t\"\\tpushq\\t%rbp\\n\"\n\t\"\\tmovq\\t%rsp, %rbp\\n\"\n\t\"\\tsubq\\t$16, %rsp\\n\"\n\t\"\\tmovl\\t%edi, -4(%rbp)\\n\"\n\t\"\\tmovl\\t-4(%rbp), %eax\\n\"\n\t\"\\tmovl\\t%eax, %esi\\n\"\n\t\"\\tleaq\t.LC0(%rip), %rdi\\n\"\n\t\"\\tmovl\t$0, %eax\\n\"\n\t\"\\tcall\tprintf@PLT\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"\\t.globl\\tmain\\n\"\n\t\"\\t.type\\tmain, @function\\n\"\n\t\"main:\\n\" \"\\tpushq\\t%rbp\\n\" \"\\tmovq\t%rsp, %rbp\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n  fputs(\"\\tmovl\t$0, %eax\\n\" \"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgloadint(int value) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(char *identifier) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", identifier, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, char *identifier) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], identifier);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(char *sym) {\n  fprintf(Outfile, \"\\t.comm\\t%s,8,8\\n\", sym);\n}\n\n// Compare two registers.\nstatic int cgcompare(int r1, int r2, char *how) {\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", how, breglist[r2]);\n  fprintf(Outfile, \"\\tandq\\t$255,%s\\n\", reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgequal(int r1, int r2) { return(cgcompare(r1, r2, \"sete\")); }\nint cgnotequal(int r1, int r2) { return(cgcompare(r1, r2, \"setne\")); }\nint cglessthan(int r1, int r2) { return(cgcompare(r1, r2, \"setl\")); }\nint cggreaterthan(int r1, int r2) { return(cgcompare(r1, r2, \"setg\")); }\nint cglessequal(int r1, int r2) { return(cgcompare(r1, r2, \"setle\")); }\nint cggreaterequal(int r1, int r2) { return(cgcompare(r1, r2, \"setge\")); }\n"
  },
  {
    "path": "07_Comparisons/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\tglobal\\tmain\\n\"\n\t\"\\textern\\tprintf\\n\"\n\t\"\\tsection\\t.text\\n\"\n\t\"LC0:\\tdb\\t\\\"%d\\\",10,0\\n\"\n\t\"printint:\\n\"\n\t\"\\tpush\\trbp\\n\"\n\t\"\\tmov\\trbp, rsp\\n\"\n\t\"\\tsub\\trsp, 16\\n\"\n\t\"\\tmov\\t[rbp-4], edi\\n\"\n\t\"\\tmov\\teax, [rbp-4]\\n\"\n\t\"\\tmov\\tesi, eax\\n\"\n\t\"\\tlea\trdi, [rel LC0]\\n\"\n\t\"\\tmov\teax, 0\\n\"\n\t\"\\tcall\tprintf\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"main:\\n\" \"\\tpush\\trbp\\n\" \"\\tmov\trbp, rsp\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n  fputs(\"\\tmov\teax, 0\\n\" \"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgloadint(int value) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(char *identifier) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], identifier);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, char *identifier) {\n  fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", identifier, reglist[r]);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(char *sym) {\n  fprintf(Outfile, \"\\tcommon\\t%s 8:8\\n\", sym);\n}\n\n// Compare two registers.\nstatic int cgcompare(int r1, int r2, char *how) {\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", how, breglist[r2]);\n  fprintf(Outfile, \"\\tand\\t%s, 255\\n\", reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgequal(int r1, int r2) { return(cgcompare(r1, r2, \"sete\")); }\nint cgnotequal(int r1, int r2) { return(cgcompare(r1, r2, \"setne\")); }\nint cglessthan(int r1, int r2) { return(cgcompare(r1, r2, \"setl\")); }\nint cggreaterthan(int r1, int r2) { return(cgcompare(r1, r2, \"setg\")); }\nint cglessequal(int r1, int r2) { return(cgcompare(r1, r2, \"setle\")); }\nint cggreaterequal(int r1, int r2) { return(cgcompare(r1, r2, \"setge\")); }\n"
  },
  {
    "path": "07_Comparisons/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t\t// Current line number\nextern_ int Putback;\t\t\t// Character put back by scanner\nextern_ FILE *Infile;\t\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n"
  },
  {
    "path": "07_Comparisons/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the declaration of a variable\nvoid var_declaration(void) {\n\n  // Ensure we have an 'int' token followed by an identifier\n  // and a semicolon. Text now has the identifier's name.\n  // Add it as a known identifier\n  match(T_INT, \"int\");\n  ident();\n  addglob(Text);\n  genglobsym(Text);\n  semi();\n}\n"
  },
  {
    "path": "07_Comparisons/decl.h",
    "content": "\n// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n// scan.c\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int intvalue);\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue);\n\n// gen.c\nint genAST(struct ASTnode *n, int reg);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\nvoid genglobsym(char *s);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nint cgloadint(int value);\nint cgloadglob(char *identifier);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nvoid cgprintint(int r);\nint cgstorglob(int r, char *identifier);\nvoid cgglobsym(char *sym);\nint cgequal(int r1, int r2);\nint cgnotequal(int r1, int r2);\nint cglessthan(int r1, int r2);\nint cggreaterthan(int r1, int r2);\nint cglessequal(int r1, int r2);\nint cggreaterequal(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nvoid statements(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name);\n\n// decl.c\nvoid var_declaration(void);\n"
  },
  {
    "path": "07_Comparisons/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_INTLIT, T_SEMI, T_ASSIGN, T_IDENT,\n  // Keywords\n  T_PRINT, T_INT\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ADD=1, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT,\n  A_IDENT, A_LVIDENT, A_ASSIGN\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  struct ASTnode *left;\t\t// Left and right child trees\n  struct ASTnode *right;\n  union {\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int id;\t\t\t// For A_IDENT, the symbol slot number\n  } v;\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n};\n"
  },
  {
    "path": "07_Comparisons/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    n = mkastleaf(A_INTLIT, Token.intvalue);\n    break;\n\n  case T_IDENT:\n    // Check that this identifier exists\n    id = findglob(Text);\n    if (id == -1)\n      fatals(\"Unknown variable\", Text);\n\n    // Make a leaf AST node for it\n    n = mkastleaf(A_IDENT, id);\n    break;\n\n  default:\n    fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into an AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int arithop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return(tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_PLUS, T_MINUS\n  20, 20,\t\t\t// T_STAR, T_SLASH\n  30, 30,\t\t\t// T_EQ, T_NE\n  40, 40, 40, 40\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the primary tree on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If we hit a semicolon, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "07_Comparisons/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given an AST, generate assembly code recursively.\n// Return the register id with the tree's final value\nint genAST(struct ASTnode *n, int reg) {\n  int leftreg, rightreg;\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, -1);\n  if (n->right)\n    rightreg = genAST(n->right, leftreg);\n\n  switch (n->op) {\n  case A_ADD:\n    return (cgadd(leftreg, rightreg));\n  case A_SUBTRACT:\n    return (cgsub(leftreg, rightreg));\n  case A_MULTIPLY:\n    return (cgmul(leftreg, rightreg));\n  case A_DIVIDE:\n    return (cgdiv(leftreg, rightreg));\n  case A_EQ:\n    return (cgequal(leftreg, rightreg));\n  case A_NE:\n    return (cgnotequal(leftreg, rightreg));\n  case A_LT:\n    return (cglessthan(leftreg, rightreg));\n  case A_GT:\n    return (cggreaterthan(leftreg, rightreg));\n  case A_LE:\n    return (cglessequal(leftreg, rightreg));\n  case A_GE:\n    return (cggreaterequal(leftreg, rightreg));\n  case A_INTLIT:\n    return (cgloadint(n->v.intvalue));\n  case A_IDENT:\n    return (cgloadglob(Gsym[n->v.id].name));\n  case A_LVIDENT:\n    return (cgstorglob(reg, Gsym[n->v.id].name));\n  case A_ASSIGN:\n    // The work has already been done, return the result\n    return (rightreg);\n  default:\n    fatald(\"Unknown AST operator\", n->op);\n  }\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\n\nvoid genglobsym(char *s) {\n  cgglobsym(s);\n}\n"
  },
  {
    "path": "07_Comparisons/input01",
    "content": "print 12 * 3;\nprint \n   18 - 2\n      * 4; print\n1 + 2 +\n  9 - 5/2 + 3*5;\n"
  },
  {
    "path": "07_Comparisons/input02",
    "content": "int fred;\nint jim;\nfred= 5;\njim= 12;\nprint fred + jim;\n"
  },
  {
    "path": "07_Comparisons/input03",
    "content": "int x;\nx= 1;     print x;\nx= x + 1; print x;\nx= x + 1; print x;\nx= x + 1; print x;\nx= x + 1; print x;\n"
  },
  {
    "path": "07_Comparisons/input04",
    "content": "int x;\nx= 7 < 9;  print x;\nx= 7 <= 9; print x;\nx= 7 != 9; print x;\nx= 7 == 7; print x;\nx= 7 >= 7; print x;\nx= 7 <= 7; print x;\nx= 9 > 7;  print x;\nx= 9 >= 7; print x;\nx= 9 != 7; print x;\n"
  },
  {
    "path": "07_Comparisons/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nvoid main(int argc, char *argv[]) {\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  statements();\t\t\t// Parse the statements in the input\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  exit(0);\n}\n"
  },
  {
    "path": "07_Comparisons/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line); exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line); exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line); exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line); exit(1);\n}\n"
  },
  {
    "path": "07_Comparisons/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n  case 'i':\n    if (!strcmp(s, \"int\"))\n      return (T_INT);\n    break;\n  case 'p':\n    if (!strcmp(s, \"print\"))\n      return (T_PRINT);\n    break;\n  }\n  return (0);\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n  case EOF:\n    t->token = T_EOF;\n    return (0);\n  case '+':\n    t->token = T_PLUS;\n    break;\n  case '-':\n    t->token = T_MINUS;\n    break;\n  case '*':\n    t->token = T_STAR;\n    break;\n  case '/':\n    t->token = T_SLASH;\n    break;\n  case ';':\n    t->token = T_SEMI;\n    break;\n  case '=':\n    if ((c = next()) == '=') {\n      t->token = T_EQ;\n    } else {\n      putback(c);\n      t->token = T_ASSIGN;\n    }\n    break;\n  case '!':\n    if ((c = next()) == '=') {\n      t->token = T_NE;\n    } else {\n      fatalc(\"Unrecognised character\", c);\n    }\n    break;\n  case '<':\n    if ((c = next()) == '=') {\n      t->token = T_LE;\n    } else {\n      putback(c);\n      t->token = T_LT;\n    }\n    break;\n  case '>':\n    if ((c = next()) == '=') {\n      t->token = T_GE;\n    } else {\n      putback(c);\n      t->token = T_GT;\n    }\n    break;\n  default:\n\n    // If it's a digit, scan the\n    // literal integer value in\n    if (isdigit(c)) {\n      t->intvalue = scanint(c);\n      t->token = T_INTLIT;\n      break;\n    } else if (isalpha(c) || '_' == c) {\n      // Read in a keyword or identifier\n      scanident(c, Text, TEXTLEN);\n\n      // If it's a recognised keyword, return that token\n      if (tokentype = keyword(Text)) {\n\tt->token = tokentype;\n\tbreak;\n      }\n      // Not a recognised keyword, so it must be an identifier\n      t->token = T_IDENT;\n      break;\n    }\n    // The character isn't part of any recognised token, error\n    fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "07_Comparisons/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// statements: statement\n//      |      statement statements\n//      ;\n//\n// statement: 'print' expression ';'\n//      |     'int'   identifier ';'\n//      |     identifier '=' expression ';'\n//      ;\n//\n// identifier: T_IDENT\n//      ;\n\nvoid print_statement(void) {\n  struct ASTnode *tree;\n  int reg;\n\n  // Match a 'print' as the first token\n  match(T_PRINT, \"print\");\n\n  // Parse the following expression and\n  // generate the assembly code\n  tree = binexpr(0);\n  reg = genAST(tree, -1);\n  genprintint(reg);\n  genfreeregs();\n\n  // Match the following semicolon\n  semi();\n}\n\nvoid assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // Check it's been defined then make a leaf node for it\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared variable\", Text);\n  }\n  right = mkastleaf(A_LVIDENT, id);\n\n  // Ensure we have an equals sign\n  match(T_ASSIGN, \"=\");\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Make an assignment AST tree\n  tree = mkastnode(A_ASSIGN, left, right, 0);\n\n  // Generate the assembly code for the assignment\n  genAST(tree, -1);\n  genfreeregs();\n\n  // Match the following semicolon\n  semi();\n}\n\n\n// Parse one or more statements\nvoid statements(void) {\n\n  while (1) {\n    switch (Token.token) {\n    case T_PRINT:\n      print_statement();\n      break;\n    case T_INT:\n      var_declaration();\n      break;\n    case T_IDENT:\n      assignment_statement();\n      break;\n    case T_EOF:\n      return;\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n    }\n  }\n}\n"
  },
  {
    "path": "07_Comparisons/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic int Globs = 0;\t\t// Position of next free global symbol slot\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table.\n// Return the slot number in the symbol table\nint addglob(char *name) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  return (y);\n}\n"
  },
  {
    "path": "07_Comparisons/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->left = left;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int intvalue) {\n  return (mkastnode(op, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue) {\n  return (mkastnode(op, left, NULL, intvalue));\n}\n"
  },
  {
    "path": "08_If_Statements/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g $(SRCN)\n\nclean:\n\trm -f comp1 compn *.o *.s out\n\ntest: comp1 input05\n\t./comp1 input05\n\tcc -o out out.s\n\t./out\n\ntestn: compn input05\n\t./compn input05\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out out.o\n\t./out\n"
  },
  {
    "path": "08_If_Statements/Readme.md",
    "content": "# Part 8: If Statements\n\nNow that we can compare values, it's time to add IF statements to our language. So,\nfirstly, let's look at the general syntax of IF statements and how they get converted\ninto assembly language.\n\n## The IF Syntax\n\nThe IF statement syntax is:\n\n```\n  if (condition is true) \n    perform this first block of code\n  else\n    perform this other block of code\n```\n\nNow, how is this normally converted into assembly language? It turns out that we\ndo the opposite comparison and jump/branch if the opposite comparison is true:\n\n```\n       perform the opposite comparison\n       jump to L1 if true\n       perform the first block of code\n       jump to L2\nL1:\n       perform the other block of code\nL2:\n   \n```\n\nwhere `L1` and `L2` are assembly language labels.\n\n## Generating The Assembly in Our Compiler\n\nRight now, we output code to set a register based on a comparison, e.g.\n\n```\n   int x; x= 7 < 9;         From input04\n```\n\nbecomes\n\n```\n        movq    $7, %r8\n        movq    $9, %r9\n        cmpq    %r9, %r8\n        setl    %r9b        Set if less than \n        andq    $255,%r9\n```\n\nBut for an IF statement, we need to jump on the opposite comparison:\n\n```\n   if (7 < 9) \n```\n\nshould become:\n\n```\n        movq    $7, %r8\n        movq    $9, %r9\n        cmpq    %r9, %r8\n        jge     L1         Jump if greater then or equal to\n        ....\nL1:\n```\n\nSo, I've implemented IF statements in this part of our journey. As this is a working\nproject, I did have to undo a few things and refactor them as part of the journey.\nI'll try to cover the changes as well as the additions along the way.\n\n## New Tokens and the Dangling Else\n\nWe are going to need a bunch of new tokens in our language. I also (for now) want to\navoid the [dangling else problem](https://en.wikipedia.org/wiki/Dangling_else). To that\nend, I've changed the grammar so that all groups of statements are wrapped around\n'{'  ... '}' curly brackets; I called such a grouping a \"compound statement\".\nWe also need '(' ... ')' parentheses to hold the IF expression, plus keywords 'if' and\n'else'. Thus, the new tokens are (in `defs.h`):\n\n```c\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  // Keywords\n  ..., T_IF, T_ELSE\n```\n\n## Scanning the Tokens\n\nThe single-character tokens should be obvious and I won't give the code to scan them.\nThe keywords should also be pretty obvious, but I'll give the scanning code from\n`keyword()` in `scan.c`:\n\n```c\n  switch (*s) {\n    case 'e':\n      if (!strcmp(s, \"else\"))\n        return (T_ELSE);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n        return (T_IF);\n      if (!strcmp(s, \"int\"))\n        return (T_INT);\n      break;\n    case 'p':\n      if (!strcmp(s, \"print\"))\n        return (T_PRINT);\n      break;\n  }\n```\n\n## The New BNF Grammar\n\nOur grammar is starting to get big, so I've rewritten it somewhat:\n\n```\n compound_statement: '{' '}'          // empty, i.e. no statement\n      |      '{' statement '}'\n      |      '{' statement statements '}'\n      ;\n\n statement: print_statement\n      |     declaration\n      |     assignment_statement\n      |     if_statement\n      ;\n\n print_statement: 'print' expression ';'  ;\n\n declaration: 'int' identifier ';'  ;\n\n assignment_statement: identifier '=' expression ';'   ;\n\n if_statement: if_head\n      |        if_head 'else' compound_statement\n      ;\n\n if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n\n identifier: T_IDENT ;\n```\n\nI've left out the definition of `true_false_expression`, but at some point when\nwe've added a few more operators I'll add it in.\n\nNote the grammar for the IF statement: it's either an `if_head` (with no 'else' clause),\nor an `if_head` followed by a 'else' and a `compound_statement`.\n\nI've separated out all the different statement types to have their own non-terminal\nname. Also, the previous `statements` non-terminal is now the `compound_statement`\nnon-terminal, and this requires '{' ... '}' around the statements.\n\nThis means that the `compound_statement` in the head is surrounded by '{' ... '}'\nand so is any `compound_statement` after the 'else' keyword. So if we have nested IF\nstatements, they have to look like:\n\n```\n  if (condition1 is true) {\n    if (condition2 is true) {\n      statements;\n    } else {\n      statements;\n    }\n  } else {\n    statements;\n  }\n```\n\nand there is no ambiguity about which 'if' each 'else' belongs to. This solves the\ndangling else problem. Later on, I'll make the '{' ... '}' optional.\n\n## Parsing Compound Statements\n\nThe old `void statements()` function is now `compound_statement()` and looks like this:\n\n```c\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    switch (Token.token) {\n      case T_PRINT:\n        tree = print_statement();\n        break;\n      case T_INT:\n        var_declaration();\n        tree = NULL;            // No AST generated here\n        break;\n      case T_IDENT:\n        tree = assignment_statement();\n        break;\n      case T_IF:\n        tree = if_statement();\n        break;\n    case T_RBRACE:\n        // When we hit a right curly bracket,\n        // skip past it and return the AST\n        rbrace();\n        return (left);\n      default:\n        fatald(\"Syntax error, token\", Token.token);\n    }\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree) {\n      if (left == NULL)\n        left = tree;\n      else\n        left = mkastnode(A_GLUE, left, NULL, tree, 0);\n    }\n  }\n```\n\nFirstly, note that the code forces the parser to match the '{' at the start of the\ncompound statement with `lbrace()`, and we can only exit when we've matched the ending\n'}' with `rbrace()`.\n\nSecondly, note that `print_statement()`, `assignment_statement()` and\n`if_statement()` all return an AST tree, as does `compound_statement()`.\nIn our old code, `print_statement()` itself called `genAST()` to evaluate the\nexpression, followed by a call to `genprintint()`. Similarly, \n`assignment_statement()`  also called `genAST()` to do the assignment.\n\nWell, this means that we have AST trees over here, and others over there. It makes some\nsense to generate just a single AST tree, and call `genAST()` once to generate the\nassembly code for it.\n\nThis isn't mandatory. For example, SubC only generates ASTs for expressions. For\nthe structural parts of the language, like statements, SubC makes specific calls\nto the code generator as I was doing in the previous versions of the compiler.\n\nI've decided to, for now, generate a single AST tree for the whole input with the\nparser. Once the input has been parsed, the assembly output can be generated from\nthe one AST tree.\n\nLater on, I'll probably generate an AST tree for each function. Later.\n\n## Parsing the IF Grammar\n\nBecause we are a recursive descent parser, parsing the IF statement is not too bad:\n\n```c\n// Parse an IF statement including\n// any optional ELSE clause\n// and return its AST\nstruct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, condAST, trueAST, falseAST, 0));\n}\n```\n\nRight now, I don't want to deal with input like `if (x-2)`, so I've limited\nthe binary expression from `binexpr()` to have a root which is one of the\nsix comparison operators A_EQ, A_NE, A_LT, A_GT, A_LE or A_GE.\n\n## The Third Child\n\nI nearly smuggled something past you without properly explaining it. In\nthe last line of `if_statement()` I build an AST node with:\n\n```c\n   mkastnode(A_IF, condAST, trueAST, falseAST, 0);\n```\n\nThat's *three* AST sub-trees! What's going on here? As you can see, the\nIF statement will have three children:\n\n  + the sub-tree that evaluates the condition\n  + the compound statement immediately following\n  + the optional compound statement after the 'else' keyword\n\nSo we now need an AST node structure with three children (in `defs.h`):\n\n```c\n// AST node types.\nenum {\n  ...\n  A_GLUE, A_IF\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\n    int intvalue;               // For A_INTLIT, the integer value\n    int id;                     // For A_IDENT, the symbol slot number\n  } v;\n};\n```\n\nThus, an A_IF tree looks like this:\n\n```\n                      IF\n                    / |  \\\n                   /  |   \\\n                  /   |    \\\n                 /    |     \\\n                /     |      \\\n               /      |       \\\n      condition   statements   statements\n```\n\n## Glue AST Nodes\n\nThere is also a new A_GLUE AST node type. What is this used for? We now\nbuild a single AST tree with lots of statements, so we need a way to\nglue them together.\n\nReview the end of the `compound_statement()` loop code:\n\n```c\n      if (left != NULL)\n        left = mkastnode(A_GLUE, left, NULL, tree, 0);\n```\n\nEach time we get a new sub-tree, we glue it on to the existing tree. So,\nfor this sequence of statements:\n\n```\n    stmt1;\n    stmt2;\n    stmt3;\n    stmt4;\n```\n\nwe end up with:\n\n```\n             A_GLUE\n              /  \\\n          A_GLUE stmt4\n            /  \\\n        A_GLUE stmt3\n          /  \\\n      stmt1  stmt2\n```\n\nAnd, as we traverse the tree depth-first left to right, this still\ngenerates the assembly code in the correct order.\n\n## The Generic Code Generator\n\nNow that our AST nodes have multiple children, our generic code generator\nis going to become a bit more complicated. Also, for the comparison\noperators, we need to know if we are doing the compare as part of an IF\nstatement (jump on the opposite comparison) or a normal expression\n(set register to 1 or 0 on the normal comparison).\n\nTo this end, I've modified `getAST()` so that we can pass in the\nparent AST nodes operation:\n\n```c\n// Given an AST, the register (if any) that holds\n// the previous rvalue, and the AST op of the parent,\n// generate assembly code recursively.\n// Return the register id with the tree's final value\nint genAST(struct ASTnode *n, int reg, int parentASTop) {\n   ...\n}\n```\n\n### Dealing with Specific AST Nodes\n\nThe code in `genAST()` now has to deal with specific AST nodes:\n\n```c\n  // We now have specific AST node handling at the top\n  switch (n->op) {\n    case A_IF:\n      return (genIFAST(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOREG, n->op);\n      genfreeregs();\n      genAST(n->right, NOREG, n->op);\n      genfreeregs();\n      return (NOREG);\n  }\n```\n\nIf we don't return, we carry on to do the normal binary operator AST nodes,\nwith one exception: the comparison nodes:\n\n```c\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF, generate a compare\n      // followed by a jump. Otherwise, compare registers and\n      // set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF)\n        return (cgcompare_and_jump(n->op, leftreg, rightreg, reg));\n      else\n        return (cgcompare_and_set(n->op, leftreg, rightreg));\n```\n\nI'll cover the new functions `cgcompare_and_jump()` and\n`cgcompare_and_set()` below.\n\n### Generating the IF Assembly Code\n\nWe deal with the A_IF AST node with a specific function, along with\na function to generate new label numbers:\n\n```c\n// Generate and return a new label number\nstatic int label(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIFAST(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = label();\n  if (n->right)\n    Lend = label();\n\n  // Generate the condition code followed\n  // by a zero jump to the false label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOREG, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOREG, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n```\n\nEffectively, the code is doing:\n\n```c\n  genAST(n->left, Lfalse, n->op);       // Condition and jump to Lfalse\n  genAST(n->mid, NOREG, n->op);         // Statements after 'if'\n  cgjump(Lend);                         // Jump to Lend\n  cglabel(Lfalse);                      // Lfalse: label\n  genAST(n->right, NOREG, n->op);       // Statements after 'else'\n  cglabel(Lend);                        // Lend: label\n```\n\n## The x86-64 Code Generation Functions\n\nSo we now have a few new x86-64 code generation functions. Some of\nthese replace the six `cgXXX()` comparison functions we created in the\nlast part of the journey.\n\nFor the normal comparison functions, we now pass in the AST operation\nto choose the relevant x86-64 `set` instruction:\n\n```c\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n```\n\nI've also found an x86-64 instruction `movzbq` that moves the lowest byte from\none register and extends it to fit into a 64-bit register. I'm using that now\ninstead of the `and $255` in the old code.\n\nWe need a functions to generate a label and to jump to it:\n\n```c\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n```\n\nFinally, we need a function to do a comparison and to jump based on\nthe opposite comparison. So, using the AST comparison node type, we\ndo the opposite comparison:\n\n```c\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n```\n\n## Testing the IF Statements\n\nDo a `make test` which compiles the `input05` file:\n\n```c\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    print i;\n  } else {\n    print j;\n  }\n}\n```\n\nHere's the resulting assembly output:\n\n```\n        movq    $6, %r8\n        movq    %r8, i(%rip)    # i=6;\n        movq    $12, %r8\n        movq    %r8, j(%rip)    # j=12;\n        movq    i(%rip), %r8\n        movq    j(%rip), %r9\n        cmpq    %r9, %r8        # Compare %r8-%r9, i.e. i-j\n        jge     L1              # Jump to L1 if i >= j\n        movq    i(%rip), %r8\n        movq    %r8, %rdi       # print i;\n        call    printint\n        jmp     L2              # Skip the else code\nL1:\n        movq    j(%rip), %r8\n        movq    %r8, %rdi       # print j;\n        call    printint\nL2:\n```\n\nAnd, of course, `make test` shows:\n\n```\ncc -o comp1 -g cg.c decl.c expr.c gen.c main.c misc.c\n      scan.c stmt.c sym.c tree.c\n./comp1 input05\ncc -o out out.s\n./out\n6                   # As 6 is less than 12\n```\n\n## Conclusion and What's Next\n\nWe've added our first control structure to our language with the IF statement. I had to\nrewrite a few existing things along the way and, given I don't have a complete\narchitectural plan in my head, I'll likely have to rewrite more things in the future.\n\nThe wrinkle for this part of the journey was that we had to perform the opposite\ncomparison for the IF decision than what we would do for the normal comparison\noperators. My solution was to inform each AST node of the node type of their parent;\nthe comparison nodes can now see if the parent is an A_IF node or not.\n\nI know that Nils Holm chose a different approach when he was implementing SubC, so\nyou should look at his code just to see this different solution to the same problem.\n\nIn the next part of our compiler writing journey, we will\nadd another control structure: the WHILE loop. [Next step](../09_While_Loops/Readme.md)\n"
  },
  {
    "path": "08_If_Statements/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\n// We need a list of byte registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\"\n\t\".LC0:\\n\"\n\t\"\\t.string\\t\\\"%d\\\\n\\\"\\n\"\n\t\"printint:\\n\"\n\t\"\\tpushq\\t%rbp\\n\"\n\t\"\\tmovq\\t%rsp, %rbp\\n\"\n\t\"\\tsubq\\t$16, %rsp\\n\"\n\t\"\\tmovl\\t%edi, -4(%rbp)\\n\"\n\t\"\\tmovl\\t-4(%rbp), %eax\\n\"\n\t\"\\tmovl\\t%eax, %esi\\n\"\n\t\"\\tleaq\t.LC0(%rip), %rdi\\n\"\n\t\"\\tmovl\t$0, %eax\\n\"\n\t\"\\tcall\tprintf@PLT\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"\\t.globl\\tmain\\n\"\n\t\"\\t.type\\tmain, @function\\n\"\n\t\"main:\\n\" \"\\tpushq\\t%rbp\\n\" \"\\tmovq\t%rsp, %rbp\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n  fputs(\"\\tmovl\t$0, %eax\\n\" \"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgloadint(int value) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(char *identifier) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", identifier, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, char *identifier) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], identifier);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(char *sym) {\n  fprintf(Outfile, \"\\t.comm\\t%s,8,8\\n\", sym);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n"
  },
  {
    "path": "08_If_Statements/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\tglobal\\tmain\\n\"\n\t\"\\textern\\tprintf\\n\"\n\t\"\\tsection\\t.text\\n\"\n\t\"LC0:\\tdb\\t\\\"%d\\\",10,0\\n\"\n\t\"printint:\\n\"\n\t\"\\tpush\\trbp\\n\"\n\t\"\\tmov\\trbp, rsp\\n\"\n\t\"\\tsub\\trsp, 16\\n\"\n\t\"\\tmov\\t[rbp-4], edi\\n\"\n\t\"\\tmov\\teax, [rbp-4]\\n\"\n\t\"\\tmov\\tesi, eax\\n\"\n\t\"\\tlea\trdi, [rel LC0]\\n\"\n\t\"\\tmov\teax, 0\\n\"\n\t\"\\tcall\tprintf\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"main:\\n\" \"\\tpush\\trbp\\n\" \"\\tmov\trbp, rsp\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n  fputs(\"\\tmov\teax, 0\\n\" \"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgloadint(int value) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(char *identifier) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], identifier);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, char *identifier) {\n  fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", identifier, reglist[r]);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(char *sym) {\n  fprintf(Outfile, \"\\tcommon\\t%s 8:8\\n\", sym);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzb\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n"
  },
  {
    "path": "08_If_Statements/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n"
  },
  {
    "path": "08_If_Statements/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the declaration of a variable\nvoid var_declaration(void) {\n\n  // Ensure we have an 'int' token followed by an identifier\n  // and a semicolon. Text now has the identifier's name.\n  // Add it as a known identifier\n  match(T_INT, \"int\");\n  ident();\n  addglob(Text);\n  genglobsym(Text);\n  semi();\n}\n"
  },
  {
    "path": "08_If_Statements/decl.h",
    "content": "\n// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n// scan.c\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int intvalue);\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue);\n\n// gen.c\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\nvoid genglobsym(char *s);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nint cgloadint(int value);\nint cgloadglob(char *identifier);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nvoid cgprintint(int r);\nint cgstorglob(int r, char *identifier);\nvoid cgglobsym(char *sym);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name);\n\n// decl.c\nvoid var_declaration(void);\n"
  },
  {
    "path": "08_If_Statements/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_INTLIT, T_SEMI, T_ASSIGN, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  // Keywords\n  T_PRINT, T_INT, T_IF, T_ELSE\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ADD = 1, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT,\n  A_IDENT, A_LVIDENT, A_ASSIGN, A_PRINT, A_GLUE, A_IF\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int id;\t\t\t// For A_IDENT, the symbol slot number\n  } v;\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n};\n"
  },
  {
    "path": "08_If_Statements/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      n = mkastleaf(A_INTLIT, Token.intvalue);\n      break;\n\n    case T_IDENT:\n      // Check that this identifier exists\n      id = findglob(Text);\n      if (id == -1)\n\tfatals(\"Unknown variable\", Text);\n\n      // Make a leaf AST node for it\n      n = mkastleaf(A_IDENT, id);\n      break;\n\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into an AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int arithop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_PLUS, T_MINUS\n  20, 20,\t\t\t// T_STAR, T_SLASH\n  30, 30,\t\t\t// T_EQ, T_NE\n  40, 40, 40, 40\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the primary tree on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon or ')', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "08_If_Statements/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int label(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIFAST(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = label();\n  if (n->right)\n    Lend = label();\n\n  // Generate the condition code followed\n  // by a zero jump to the false label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOREG, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOREG, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Given an AST, the register (if any) that holds\n// the previous rvalue, and the AST op of the parent,\n// generate assembly code recursively.\n// Return the register id with the tree's final value\nint genAST(struct ASTnode *n, int reg, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We now have specific AST node handling at the top\n  switch (n->op) {\n    case A_IF:\n      return (genIFAST(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOREG, n->op);\n      genfreeregs();\n      genAST(n->right, NOREG, n->op);\n      genfreeregs();\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOREG, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, leftreg, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF, generate a compare\n      // followed by a jump. Otherwise, compare registers and\n      // set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, reg));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue));\n    case A_IDENT:\n      return (cgloadglob(Gsym[n->v.id].name));\n    case A_LVIDENT:\n      return (cgstorglob(reg, Gsym[n->v.id].name));\n    case A_ASSIGN:\n      // The work has already been done, return the result\n      return (rightreg);\n    case A_PRINT:\n      // Print the left-child's value\n      // and return no register\n      genprintint(leftreg);\n      genfreeregs();\n      return (NOREG);\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\n\nvoid genglobsym(char *s) {\n  cgglobsym(s);\n}\n"
  },
  {
    "path": "08_If_Statements/input01",
    "content": "{ print 12 * 3;\n  print 18 - 2 * 4;\n  print 1 + 2 + 9 - 5/2 + 3*5;\n}\n"
  },
  {
    "path": "08_If_Statements/input02",
    "content": "{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  print fred + jim;\n}\n"
  },
  {
    "path": "08_If_Statements/input03",
    "content": "{\n  int x;\n  x= 1;     print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n}\n"
  },
  {
    "path": "08_If_Statements/input04",
    "content": "{\n  int x;\n  x= 7 < 9;  print x;\n  x= 7 <= 9; print x;\n  x= 7 != 9; print x;\n  x= 7 == 7; print x;\n  x= 7 >= 7; print x;\n  x= 7 <= 7; print x;\n  x= 9 > 7;  print x;\n  x= 9 >= 7; print x;\n  x= 9 != 7; print x;\n}\n"
  },
  {
    "path": "08_If_Statements/input05",
    "content": "{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    print i;\n  } else {\n    print j;\n  }\n}\n"
  },
  {
    "path": "08_If_Statements/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nvoid main(int argc, char *argv[]) {\n  struct ASTnode *tree;\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  tree = compound_statement();\t// Parse the compound statement in the input\n  genAST(tree, NOREG, 0);\t// Generate the assembly code for it\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  exit(0);\n}\n"
  },
  {
    "path": "08_If_Statements/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "08_If_Statements/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'p':\n      if (!strcmp(s, \"print\"))\n\treturn (T_PRINT);\n      break;\n  }\n  return (0);\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tfatalc(\"Unrecognised character\", c);\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif (tokentype = keyword(Text)) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "08_If_Statements/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: print_statement\n//      |     declaration\n//      |     assignment_statement\n//      |     if_statement\n//      ;\n//\n// print_statement: 'print' expression ';'  ;\n//\n// declaration: 'int' identifier ';'  ;\n//\n// assignment_statement: identifier '=' expression ';'   ;\n//\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// identifier: T_IDENT ;\n\nstatic struct ASTnode *print_statement(void) {\n  struct ASTnode *tree;\n  int reg;\n\n  // Match a 'print' as the first token\n  match(T_PRINT, \"print\");\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Make an print AST tree\n  tree = mkastunary(A_PRINT, tree, 0);\n\n  // Match the following semicolon\n  // and return the AST\n  semi();\n  return (tree);\n}\n\nstatic struct ASTnode *assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // Check it's been defined then make a leaf node for it\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared variable\", Text);\n  }\n  right = mkastleaf(A_LVIDENT, id);\n\n  // Ensure we have an equals sign\n  match(T_ASSIGN, \"=\");\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Make an assignment AST tree\n  tree = mkastnode(A_ASSIGN, left, NULL, right, 0);\n\n  // Match the following semicolon\n  // and return the AST\n  semi();\n  return (tree);\n}\n\n// Parse an IF statement including\n// any optional ELSE clause\n// and return its AST\nstruct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, condAST, trueAST, falseAST, 0));\n}\n\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    switch (Token.token) {\n      case T_PRINT:\n\ttree = print_statement();\n\tbreak;\n      case T_INT:\n\tvar_declaration();\n\ttree = NULL;\t\t// No AST generated here\n\tbreak;\n      case T_IDENT:\n\ttree = assignment_statement();\n\tbreak;\n      case T_IF:\n\ttree = if_statement();\n\tbreak;\n      case T_RBRACE:\n\t// When we hit a right curly bracket,\n\t// skip past it and return the AST\n\trbrace();\n\treturn (left);\n      default:\n\tfatald(\"Syntax error, token\", Token.token);\n    }\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, left, NULL, tree, 0);\n    }\n  }\n}\n"
  },
  {
    "path": "08_If_Statements/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic int Globs = 0;\t\t// Position of next free global symbol slot\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table.\n// Return the slot number in the symbol table\nint addglob(char *name) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  return (y);\n}\n"
  },
  {
    "path": "08_If_Statements/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int intvalue) {\n  return (mkastnode(op, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue) {\n  return (mkastnode(op, left, NULL, NULL, intvalue));\n}\n"
  },
  {
    "path": "09_While_Loops/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g $(SRCN)\n\nclean:\n\trm -f comp1 compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntest6: comp1 tests/input06\n\t./comp1 tests/input06\n\tcc -o out out.s\n\t./out\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\ntest6n: compn tests/input06\n\t./compn tests/input06\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out out.o\n\t./out\n"
  },
  {
    "path": "09_While_Loops/Readme.md",
    "content": "# Part 9: While Loops\n\nIn this part of the journey we are going to add WHILE loops to our\nlanguage. In some sense, a WHILE loop is very much like an IF statement\nwithout an 'else' clause, except that we always jump back to the top\nof the loop.\n\nSo, this:\n\n```\n  while (condition is true) {\n    statements;\n  }\n```\n\nshould get translated to:\n\n```\nLstart: evaluate condition\n\tjump to Lend if condition false\n\tstatements\n\tjump to Lstart\nLend:\n```\n\nThis means that we can borrow the scanning, parsing and code generation\nstructures that we used with IF statements and make some small changes\nto also deal with WHILE statements.\n\nLet's see how we make this happen.\n\n## New Tokens\n\nWe need a new token, T_WHILE, for the new 'while' keyword. The changes\nto `defs.h` and `scan.c` are obvious so I'll omit them here.\n\n## Parsing the While Syntax\n\nThe BNF grammar for the WHILE loop is:\n\n```\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n```\n\nand we need a function in `stmt.c` to parse this. Here it is; note the\nsimplicity of this compared to the parsing of IF statements:\n\n```c\n// Parse a WHILE statement\n// and return its AST\nstruct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, condAST, NULL, bodyAST, 0));\n}\n```\n\nWe need a new AST node type, A_WHILE, which has been added to `defs.h`.\nThis node has a left child sub-tree to evaluate the condition, and a\nright child sub-tree for the compound statement which is the body of the\nWHILE loop.\n\n## Generic Code Generation\n\nWe need to create a start and end label, evaluate the condition and\ninsert appropriate jumps to exit the loop and to return to the top of the\nloop. Again, this is much simpler than the code to generate IF statements.\nIn `gen.c`:\n\n```c\n// Generate the code for a WHILE statement\n// and an optional ELSE clause\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = label();\n  Lend = label();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOREG, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n```\n\nOne thing I had to do was recognise that the parent AST node\nof the comparison operators could now be A_WHILE, so in `genAST()`\nthe code for the comparison operators looks like:\n\n```c\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate \n      // a compare followed by a jump. Otherwise, compare registers \n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n        return (cgcompare_and_jump(n->op, leftreg, rightreg, reg));\n      else\n        return (cgcompare_and_set(n->op, leftreg, rightreg));\n```\n\nAnd that, altogether, is all we need to implement WHILE loops!\n\n## Testing the New Language Additions\n\nI've moved all of the input files into a `test/` directory. If you now\ndo `make test`, it will go into this directory, compile each input\nand compare the output against known-good output:\n\n```\ncc -o comp1 -g cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c\n      sym.c tree.c\n(cd tests; chmod +x runtests; ./runtests)\ninput01: OK\ninput02: OK\ninput03: OK\ninput04: OK\ninput05: OK\ninput06: OK\n```\n\nYou can also do a `make test6`. This compiles the `tests/input06` file:\n\n```c\n{ int i;\n  i=1;\n  while (i <= 10) {\n    print i;\n    i= i + 1;\n  }\n}\n```\n\nThis will print out the numbers from 1 to 10:\n\n```\ncc -o comp1 -g cg.c decl.c expr.c gen.c main.c misc.c scan.c\n      stmt.c sym.c tree.c\n./comp1 tests/input06\ncc -o out out.s\n./out\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n```\n\nAnd here is the assembly output from the compilation:\n\n```\n\t.comm\ti,8,8\n\tmovq\t$1, %r8\n\tmovq\t%r8, i(%rip)\t\t# i= 1\nL1:\n\tmovq\ti(%rip), %r8\n\tmovq\t$10, %r9\n\tcmpq\t%r9, %r8\t\t# Is i <= 10?\n\tjg\tL2\t\t\t# Greater than, jump to L2\n\tmovq\ti(%rip), %r8\n\tmovq\t%r8, %rdi\t\t# Print out i\n\tcall\tprintint\n\tmovq\ti(%rip), %r8\n\tmovq\t$1, %r9\n\taddq\t%r8, %r9\t\t# Add 1 to i\n\tmovq\t%r9, i(%rip)\n\tjmp\tL1\t\t\t# and loop back\nL2:\n```\n\n\n## Conclusion and What's Next\n\nThe WHILE loop was easy to add, once we had already done the IF statement\nas they share a lot of similarities.\n\nI think we also now have a\n[Turing-complete](https://en.wikipedia.org/wiki/Turing_completeness)\nlanguage:\n\n  + an infinite amount of storage, i.e. an infinite number of variables\n  + the ability to make decisions based on stored values, i.e. IF statements\n  + the ability to change directions, i.e. WHILE loops\n\nSo we can stop now, our job is done! No, of course not. We are still\nworking towards getting the compiler to compile itself.\n\nIn the next part of our compiler writing journey, we will add FOR loops\nto the language. [Next step](../10_For_Loops/Readme.md)\n"
  },
  {
    "path": "09_While_Loops/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\n// We need a list of byte registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\"\n\t\".LC0:\\n\"\n\t\"\\t.string\\t\\\"%d\\\\n\\\"\\n\"\n\t\"printint:\\n\"\n\t\"\\tpushq\\t%rbp\\n\"\n\t\"\\tmovq\\t%rsp, %rbp\\n\"\n\t\"\\tsubq\\t$16, %rsp\\n\"\n\t\"\\tmovl\\t%edi, -4(%rbp)\\n\"\n\t\"\\tmovl\\t-4(%rbp), %eax\\n\"\n\t\"\\tmovl\\t%eax, %esi\\n\"\n\t\"\\tleaq\t.LC0(%rip), %rdi\\n\"\n\t\"\\tmovl\t$0, %eax\\n\"\n\t\"\\tcall\tprintf@PLT\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"\\t.globl\\tmain\\n\"\n\t\"\\t.type\\tmain, @function\\n\"\n\t\"main:\\n\" \"\\tpushq\\t%rbp\\n\" \"\\tmovq\t%rsp, %rbp\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n  fputs(\"\\tmovl\t$0, %eax\\n\" \"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgloadint(int value) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(char *identifier) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", identifier, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, char *identifier) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], identifier);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(char *sym) {\n  fprintf(Outfile, \"\\t.comm\\t%s,8,8\\n\", sym);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n"
  },
  {
    "path": "09_While_Loops/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\tglobal\\tmain\\n\"\n\t\"\\textern\\tprintf\\n\"\n\t\"\\tsection\\t.text\\n\"\n\t\"LC0:\\tdb\\t\\\"%d\\\",10,0\\n\"\n\t\"printint:\\n\"\n\t\"\\tpush\\trbp\\n\"\n\t\"\\tmov\\trbp, rsp\\n\"\n\t\"\\tsub\\trsp, 16\\n\"\n\t\"\\tmov\\t[rbp-4], edi\\n\"\n\t\"\\tmov\\teax, [rbp-4]\\n\"\n\t\"\\tmov\\tesi, eax\\n\"\n\t\"\\tlea\trdi, [rel LC0]\\n\"\n\t\"\\tmov\teax, 0\\n\"\n\t\"\\tcall\tprintf\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"main:\\n\" \"\\tpush\\trbp\\n\" \"\\tmov\trbp, rsp\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n  fputs(\"\\tmov\teax, 0\\n\" \"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgloadint(int value) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(char *identifier) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], identifier);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, char *identifier) {\n  fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", identifier, reglist[r]);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(char *sym) {\n  fprintf(Outfile, \"\\tcommon\\t%s 8:8\\n\", sym);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n"
  },
  {
    "path": "09_While_Loops/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n"
  },
  {
    "path": "09_While_Loops/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// declaration: 'int' identifier ';'  ;\n//\n// Parse the declaration of a variable\nvoid var_declaration(void) {\n\n  // Ensure we have an 'int' token followed by an identifier\n  // and a semicolon. Text now has the identifier's name.\n  // Add it as a known identifier\n  match(T_INT, \"int\");\n  ident();\n  addglob(Text);\n  genglobsym(Text);\n  semi();\n}\n"
  },
  {
    "path": "09_While_Loops/decl.h",
    "content": "\n// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n// scan.c\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int intvalue);\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue);\n\n// gen.c\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\nvoid genglobsym(char *s);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nint cgloadint(int value);\nint cgloadglob(char *identifier);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nvoid cgprintint(int r);\nint cgstorglob(int r, char *identifier);\nvoid cgglobsym(char *sym);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name);\n\n// decl.c\nvoid var_declaration(void);\n"
  },
  {
    "path": "09_While_Loops/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_INTLIT, T_SEMI, T_ASSIGN, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  // Keywords\n  T_PRINT, T_INT, T_IF, T_ELSE, T_WHILE\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ADD = 1, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT,\n  A_IDENT, A_LVIDENT, A_ASSIGN, A_PRINT, A_GLUE,\n  A_IF, A_WHILE\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int id;\t\t\t// For A_IDENT, the symbol slot number\n  } v;\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n};\n"
  },
  {
    "path": "09_While_Loops/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      n = mkastleaf(A_INTLIT, Token.intvalue);\n      break;\n\n    case T_IDENT:\n      // Check that this identifier exists\n      id = findglob(Text);\n      if (id == -1)\n\tfatals(\"Unknown variable\", Text);\n\n      // Make a leaf AST node for it\n      n = mkastleaf(A_IDENT, id);\n      break;\n\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into an AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int arithop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_PLUS, T_MINUS\n  20, 20,\t\t\t// T_STAR, T_SLASH\n  30, 30,\t\t\t// T_EQ, T_NE\n  40, 40, 40, 40\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the primary tree on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon or ')', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "09_While_Loops/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int label(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = label();\n  if (n->right)\n    Lend = label();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOREG, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOREG, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\n// and an optional ELSE clause\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = label();\n  Lend = label();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOREG, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, the register (if any) that holds\n// the previous rvalue, and the AST op of the parent,\n// generate assembly code recursively.\n// Return the register id with the tree's final value\nint genAST(struct ASTnode *n, int reg, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We now have specific AST node handling at the top\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOREG, n->op);\n      genfreeregs();\n      genAST(n->right, NOREG, n->op);\n      genfreeregs();\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOREG, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, leftreg, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, reg));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue));\n    case A_IDENT:\n      return (cgloadglob(Gsym[n->v.id].name));\n    case A_LVIDENT:\n      return (cgstorglob(reg, Gsym[n->v.id].name));\n    case A_ASSIGN:\n      // The work has already been done, return the result\n      return (rightreg);\n    case A_PRINT:\n      // Print the left-child's value\n      // and return no register\n      genprintint(leftreg);\n      genfreeregs();\n      return (NOREG);\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\n\nvoid genglobsym(char *s) {\n  cgglobsym(s);\n}\n"
  },
  {
    "path": "09_While_Loops/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nvoid main(int argc, char *argv[]) {\n  struct ASTnode *tree;\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  tree = compound_statement();\t// Parse the compound statement in the input\n  genAST(tree, NOREG, 0);\t// Generate the assembly code for it\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  exit(0);\n}\n"
  },
  {
    "path": "09_While_Loops/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "09_While_Loops/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'p':\n      if (!strcmp(s, \"print\"))\n\treturn (T_PRINT);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tfatalc(\"Unrecognised character\", c);\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif (tokentype = keyword(Text)) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "09_While_Loops/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: print_statement\n//      |     declaration\n//      |     assignment_statement\n//      |     if_statement\n//      |     while_statement\n//      ;\n\n// print_statement: 'print' expression ';'  ;\n//\nstatic struct ASTnode *print_statement(void) {\n  struct ASTnode *tree;\n  int reg;\n\n  // Match a 'print' as the first token\n  match(T_PRINT, \"print\");\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Make an print AST tree\n  tree = mkastunary(A_PRINT, tree, 0);\n\n  // Match the following semicolon\n  // and return the AST\n  semi();\n  return (tree);\n}\n\n// assignment_statement: identifier '=' expression ';'   ;\n//\nstatic struct ASTnode *assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // Check it's been defined then make a leaf node for it\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared variable\", Text);\n  }\n  right = mkastleaf(A_LVIDENT, id);\n\n  // Ensure we have an equals sign\n  match(T_ASSIGN, \"=\");\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Make an assignment AST tree\n  tree = mkastnode(A_ASSIGN, left, NULL, right, 0);\n\n  // Match the following semicolon\n  // and return the AST\n  semi();\n  return (tree);\n}\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including\n// any optional ELSE clause\n// and return its AST\nstruct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement\n// and return its AST\nstruct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, condAST, NULL, bodyAST, 0));\n}\n\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    switch (Token.token) {\n      case T_PRINT:\n\ttree = print_statement();\n\tbreak;\n      case T_INT:\n\tvar_declaration();\n\ttree = NULL;\t\t// No AST generated here\n\tbreak;\n      case T_IDENT:\n\ttree = assignment_statement();\n\tbreak;\n      case T_IF:\n\ttree = if_statement();\n\tbreak;\n      case T_WHILE:\n\ttree = while_statement();\n\tbreak;\n      case T_RBRACE:\n\t// When we hit a right curly bracket,\n\t// skip past it and return the AST\n\trbrace();\n\treturn (left);\n      default:\n\tfatald(\"Syntax error, token\", Token.token);\n    }\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, left, NULL, tree, 0);\n    }\n  }\n}\n"
  },
  {
    "path": "09_While_Loops/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic int Globs = 0;\t\t// Position of next free global symbol slot\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table.\n// Return the slot number in the symbol table\nint addglob(char *name) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  return (y);\n}\n"
  },
  {
    "path": "09_While_Loops/tests/input01",
    "content": "{ print 12 * 3;\n  print 18 - 2 * 4;\n  print 1 + 2 + 9 - 5/2 + 3*5;\n}\n"
  },
  {
    "path": "09_While_Loops/tests/input02",
    "content": "{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  print fred + jim;\n}\n"
  },
  {
    "path": "09_While_Loops/tests/input03",
    "content": "{\n  int x;\n  x= 1;     print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n}\n"
  },
  {
    "path": "09_While_Loops/tests/input04",
    "content": "{\n  int x;\n  x= 7 < 9;  print x;\n  x= 7 <= 9; print x;\n  x= 7 != 9; print x;\n  x= 7 == 7; print x;\n  x= 7 >= 7; print x;\n  x= 7 <= 7; print x;\n  x= 9 > 7;  print x;\n  x= 9 >= 7; print x;\n  x= 9 != 7; print x;\n}\n"
  },
  {
    "path": "09_While_Loops/tests/input05",
    "content": "{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    print i;\n  } else {\n    print j;\n  }\n}\n"
  },
  {
    "path": "09_While_Loops/tests/input06",
    "content": "{ int i;\n  i=1;\n  while (i <= 10) {\n    print i;\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "09_While_Loops/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then\n     ../comp1 $i\n     cc -o out out.s\n     ./out > out.$i\n     rm -f out out.s\n   fi\ndone\n"
  },
  {
    "path": "09_While_Loops/tests/mktestsn",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -o out out.o\n     ./out > out.$i\n     rm -f out out.s\n   fi\ndone\n"
  },
  {
    "path": "09_While_Loops/tests/out.input01",
    "content": "36\n10\n25\n"
  },
  {
    "path": "09_While_Loops/tests/out.input02",
    "content": "17\n"
  },
  {
    "path": "09_While_Loops/tests/out.input03",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "09_While_Loops/tests/out.input04",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "09_While_Loops/tests/out.input05",
    "content": "6\n"
  },
  {
    "path": "09_While_Loops/tests/out.input06",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "09_While_Loops/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "09_While_Loops/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -o out out.o\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "09_While_Loops/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int intvalue) {\n  return (mkastnode(op, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue) {\n  return (mkastnode(op, left, NULL, NULL, intvalue));\n}\n"
  },
  {
    "path": "10_For_Loops/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g $(SRCN)\n\nclean:\n\trm -f comp1 compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntest7: comp1 tests/input07\n\t./comp1 tests/input07\n\tcc -o out out.s\n\t./out\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\ntest7n: compn tests/input07\n\t./compn tests/input07\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out out.o\n\t./out\n"
  },
  {
    "path": "10_For_Loops/Readme.md",
    "content": "# Part 10: FOR Loops\n\nIn this part of our compiler writing journey I'm going to add FOR loops.\nThere is a wrinkle to work out in terms of implementation which I want\nto explain before I get to the discussion on how it got solved.\n\n## The FOR Loop Syntax\n\nI assume that you are familiar with the syntax of FOR loops. One example is\n\n```c\n  for (i=0; i < MAX; i++)\n    printf(\"%d\\n\", i);\n```\n\nI'm going to use this BNF syntax for our language:\n\n```\n for_statement: 'for' '(' preop_statement ';'\n                          true_false_expression ';'\n                          postop_statement ')' compound_statement  ;\n\n preop_statement:  statement  ;        (for now)\n postop_statement: statement  ;        (for now)\n```\n\nThe `preop_statement` is run before the loop starts. Later on, we will\nhave to limit exactly what sort of actions can be performed here (e.g. no\nIF statements). Then the `true_false_expression` is evaluated. If true\nthe loop executes the `compound_statement`. Once this is done, the\n`postop_statement` is performed and the code loops back to redo the\n`true_false_expression`.\n\n## The Wrinkle\n\nThe wrinkle is that the `postop_statement` is parsed before the\n`compound_statement`, but we have to generate the code for the\n`postop_statement` *after* the code for the `compound_statement`.\n\nThere are several ways to solve this problem. When I wrote a previous\ncompiler, I chose to put the `compound_statement` assembly code in\na temporary buffer, and \"play back\" the buffer once I'd generated\nthe code for the `postop_statement`. In the SubC compiler, Nils\nmakes clever use of labels and jumps to labels to \"thread\" the code's\nexecution to enforce the correct sequence.\n\nBut we build an AST tree here. Let's use it to get the generated assembly\ncode in the correct sequence.\n\n## What Sort of AST Tree?\n\nYou might have noticed that a FOR loop has four structural components:\n\n 1. The `preop_statement`\n 2. The `true_false_expression`\n 3. The `postop_statement`\n 4. The `compound_statement`\n\nI don't really want to change the AST node structure yet again to have\nfour children. But we can visualise a FOR loop as an augmented WHILE loop:\n\n```\n   preop_statement;\n   while ( true_false_expression ) {\n     compound_statement;\n     postop_statement;\n   }\n```\n\nCan we build an AST tree with our existing node types to reflect this\nstructure? Yes:\n\n```\n         A_GLUE\n        /     \\\n   preop     A_WHILE\n             /    \\\n        decision  A_GLUE\n                  /    \\\n            compound  postop\n```\n\nManually traverse this tree top-down left-to-right and convince yourself\nthat we will generate the assembly code in the right order.\nWe had to glue the `compound_statement` and the `postop_statement`\ntogether so that, when the WHILE loop exits, it will skip over both the\n`compound_statement` and the `postop_statement`.\n\nThis also means that we need a new T_FOR token but we won't need a new\nAST node type. So the only compiler change will be scanning and parsing.\n\n## Tokens and Scanning\n\nThere is a new keyword 'for' and an associated token, T_FOR. No\nbig changes here.\n\n## Parsing Statements\n\nWe do need to make a structural change to the parser. For the FOR\ngrammar, I only want a single statement as the `preop_statement`\nand the `postop_statement`. Right now, we have a `compound_statement()`\nfunction that simply loops until it hits a right curly bracket '}'.\nWe need to separate this out so `compound_statement()` calls\n`single_statement()` to get one statement.\n\nBut there's another wrinkle. Take the existing parsing of assignment\nstatements in `assignment_statement()`. The parser must find a semicolon\nat the end of the statement.\n\nThat's good for compound statements but it won't work for FOR loops.\nI would have to write something like:\n\n```c\n  for (i=1 ; i < 10 ; i= i + 1; )\n```\n\nbecause each assignment statement *must* end with a semicolon.\n\nWhat we need is for the single statement parser *not* to scan in the\nsemicolon, but to leave that up to the compound statement parser.\nAnd we scan in semicolons for some statements (e.g. between assignment\nstatements) and not for other statements (e.g. not between successive\nIF statements). \n\nWith all of that explained, let's now look at the new single and compound\nstatement parsing code:\n\n```c\n// Parse a single statement\n// and return its AST\nstatic struct ASTnode *single_statement(void) {\n  switch (Token.token) {\n    case T_PRINT:\n      return (print_statement());\n    case T_INT:\n      var_declaration();\n      return (NULL);\t\t// No AST generated here\n    case T_IDENT:\n      return (assignment_statement());\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL &&\n\t(tree->op == A_PRINT || tree->op == A_ASSIGN))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n```\n\nI've also removed the calls to `semi()` in `print_statement()` and\n`assignment_statement()`.\n\n## Parsing FOR Loops\n\nGiven the BNF syntax for FOR loops above, this is straightforward. And\ngiven the shape of the AST tree we want, the code to build this tree is\nalso straightforward. Here's the code:\n\n```c\n// Parse a FOR statement\n// and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST= single_statement();\n  semi();\n\n  // Get the condition and the ';'\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST= single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree= mkastnode(A_GLUE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree= mkastnode(A_WHILE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return(mkastnode(A_GLUE, preopAST, NULL, tree, 0));\n}\n```\n\n## Generating the Assembly Code\n\nWell, all we have done is synthesized a tree which has a WHILE loop\nin it with some sub-trees glued together, so there are no changes\nto the generation side of the compiler.\n\n## Trying It Out\n\nThe `tests/input07` file has this program in it:\n\n```c\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n```\n\nWhen we do `make test7`, we get this output:\n\n```\ncc -o comp1 -g cg.c decl.c expr.c gen.c main.c misc.c scan.c\n    stmt.c sym.c tree.c\n./comp1 tests/input07\ncc -o out out.s\n./out\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n```\n\nand here is the relevant assembly output:\n\n```\n\t.comm\ti,8,8\n\tmovq\t$1, %r8\n\tmovq\t%r8, i(%rip)\t\t# i = 1\nL1:\n\tmovq\ti(%rip), %r8\n\tmovq\t$10, %r9\n\tcmpq\t%r9, %r8\t\t# Is i < 10?\n\tjg\tL2\t\t\t# i >= 10, jump to L2\n\tmovq\ti(%rip), %r8\n\tmovq\t%r8, %rdi\n\tcall\tprintint\t\t# print i\n\tmovq\ti(%rip), %r8\n\tmovq\t$1, %r9\n\taddq\t%r8, %r9\t\t# i = i + 1\n\tmovq\t%r9, i(%rip)\n\tjmp\tL1\t\t\t# Jump to top of loop\nL2:\n```\n\n## Conclusion and What's Next\n\nWe now have a reasonable number of control structures in our language:\nIF statements, WHILE loops and FOR loops. The question is, what to\ntackle next? There are so many things we could look at:\n\n + types\n + local versus global things\n + functions\n + arrays and pointers\n + structures and unions\n + auto, static and friends\n\nI've decided to look at functions. So,\nin the next part of our compiler writing journey, we will begin\nthe first of several stages to add functions to our language. [Next step](../11_Functions_pt1/Readme.md)\n"
  },
  {
    "path": "10_For_Loops/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\n// We need a list of byte registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\"\n\t\".LC0:\\n\"\n\t\"\\t.string\\t\\\"%d\\\\n\\\"\\n\"\n\t\"printint:\\n\"\n\t\"\\tpushq\\t%rbp\\n\"\n\t\"\\tmovq\\t%rsp, %rbp\\n\"\n\t\"\\tsubq\\t$16, %rsp\\n\"\n\t\"\\tmovl\\t%edi, -4(%rbp)\\n\"\n\t\"\\tmovl\\t-4(%rbp), %eax\\n\"\n\t\"\\tmovl\\t%eax, %esi\\n\"\n\t\"\\tleaq\t.LC0(%rip), %rdi\\n\"\n\t\"\\tmovl\t$0, %eax\\n\"\n\t\"\\tcall\tprintf@PLT\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"\\t.globl\\tmain\\n\"\n\t\"\\t.type\\tmain, @function\\n\"\n\t\"main:\\n\" \"\\tpushq\\t%rbp\\n\" \"\\tmovq\t%rsp, %rbp\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n  fputs(\"\\tmovl\t$0, %eax\\n\" \"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgloadint(int value) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(char *identifier) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", identifier, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, char *identifier) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], identifier);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(char *sym) {\n  fprintf(Outfile, \"\\t.comm\\t%s,8,8\\n\", sym);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n"
  },
  {
    "path": "10_For_Loops/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\tglobal\\tmain\\n\"\n\t\"\\textern\\tprintf\\n\"\n\t\"\\tsection\\t.text\\n\"\n\t\"LC0:\\tdb\\t\\\"%d\\\",10,0\\n\"\n\t\"printint:\\n\"\n\t\"\\tpush\\trbp\\n\"\n\t\"\\tmov\\trbp, rsp\\n\"\n\t\"\\tsub\\trsp, 16\\n\"\n\t\"\\tmov\\t[rbp-4], edi\\n\"\n\t\"\\tmov\\teax, [rbp-4]\\n\"\n\t\"\\tmov\\tesi, eax\\n\"\n\t\"\\tlea\trdi, [rel LC0]\\n\"\n\t\"\\tmov\teax, 0\\n\"\n\t\"\\tcall\tprintf\\n\"\n\t\"\\tnop\\n\"\n\t\"\\tleave\\n\"\n\t\"\\tret\\n\"\n\t\"\\n\"\n\t\"main:\\n\" \"\\tpush\\trbp\\n\" \"\\tmov\trbp, rsp\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n  fputs(\"\\tmov\teax, 0\\n\" \"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgloadint(int value) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(char *identifier) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], identifier);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, char *identifier) {\n  fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", identifier, reglist[r]);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(char *sym) {\n  fprintf(Outfile, \"\\tcommon\\t%s 8:8\\n\", sym);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n"
  },
  {
    "path": "10_For_Loops/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n"
  },
  {
    "path": "10_For_Loops/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// declaration: 'int' identifier ';'  ;\n//\n// Parse the declaration of a variable\nvoid var_declaration(void) {\n\n  // Ensure we have an 'int' token followed by an identifier\n  // and a semicolon. Text now has the identifier's name.\n  // Add it as a known identifier\n  match(T_INT, \"int\");\n  ident();\n  addglob(Text);\n  genglobsym(Text);\n  semi();\n}\n"
  },
  {
    "path": "10_For_Loops/decl.h",
    "content": "\n// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n// scan.c\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int intvalue);\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue);\n\n// gen.c\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\nvoid genglobsym(char *s);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nint cgloadint(int value);\nint cgloadglob(char *identifier);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nvoid cgprintint(int r);\nint cgstorglob(int r, char *identifier);\nvoid cgglobsym(char *sym);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name);\n\n// decl.c\nvoid var_declaration(void);\n"
  },
  {
    "path": "10_For_Loops/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_INTLIT, T_SEMI, T_ASSIGN, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  // Keywords\n  T_PRINT, T_INT, T_IF, T_ELSE, T_WHILE,\n  T_FOR\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ADD = 1, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT,\n  A_IDENT, A_LVIDENT, A_ASSIGN, A_PRINT, A_GLUE,\n  A_IF, A_WHILE\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int id;\t\t\t// For A_IDENT, the symbol slot number\n  } v;\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n};\n"
  },
  {
    "path": "10_For_Loops/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      n = mkastleaf(A_INTLIT, Token.intvalue);\n      break;\n\n    case T_IDENT:\n      // Check that this identifier exists\n      id = findglob(Text);\n      if (id == -1)\n\tfatals(\"Unknown variable\", Text);\n\n      // Make a leaf AST node for it\n      n = mkastleaf(A_IDENT, id);\n      break;\n\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into an AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int arithop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_PLUS, T_MINUS\n  20, 20,\t\t\t// T_STAR, T_SLASH\n  30, 30,\t\t\t// T_EQ, T_NE\n  40, 40, 40, 40\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the primary tree on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon or ')', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "10_For_Loops/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int label(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = label();\n  if (n->right)\n    Lend = label();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOREG, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOREG, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\n// and an optional ELSE clause\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = label();\n  Lend = label();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOREG, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, the register (if any) that holds\n// the previous rvalue, and the AST op of the parent,\n// generate assembly code recursively.\n// Return the register id with the tree's final value\nint genAST(struct ASTnode *n, int reg, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We now have specific AST node handling at the top\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOREG, n->op);\n      genfreeregs();\n      genAST(n->right, NOREG, n->op);\n      genfreeregs();\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOREG, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, leftreg, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, reg));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue));\n    case A_IDENT:\n      return (cgloadglob(Gsym[n->v.id].name));\n    case A_LVIDENT:\n      return (cgstorglob(reg, Gsym[n->v.id].name));\n    case A_ASSIGN:\n      // The work has already been done, return the result\n      return (rightreg);\n    case A_PRINT:\n      // Print the left-child's value\n      // and return no register\n      genprintint(leftreg);\n      genfreeregs();\n      return (NOREG);\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\n\nvoid genglobsym(char *s) {\n  cgglobsym(s);\n}\n"
  },
  {
    "path": "10_For_Loops/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nvoid main(int argc, char *argv[]) {\n  struct ASTnode *tree;\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  tree = compound_statement();\t// Parse the compound statement in the input\n  genAST(tree, NOREG, 0);\t// Generate the assembly code for it\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  exit(0);\n}\n"
  },
  {
    "path": "10_For_Loops/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "10_For_Loops/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'p':\n      if (!strcmp(s, \"print\"))\n\treturn (T_PRINT);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tfatalc(\"Unrecognised character\", c);\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif (tokentype = keyword(Text)) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "10_For_Loops/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: print_statement\n//      |     declaration\n//      |     assignment_statement\n//      |     if_statement\n//      |     while_statement\n//      ;\n\n// print_statement: 'print' expression ';'  ;\n//\nstatic struct ASTnode *print_statement(void) {\n  struct ASTnode *tree;\n  int reg;\n\n  // Match a 'print' as the first token\n  match(T_PRINT, \"print\");\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Make an print AST tree\n  tree = mkastunary(A_PRINT, tree, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// assignment_statement: identifier '=' expression ';'   ;\n//\nstatic struct ASTnode *assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // Check it's been defined then make a leaf node for it\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared variable\", Text);\n  }\n  right = mkastleaf(A_LVIDENT, id);\n\n  // Ensure we have an equals sign\n  match(T_ASSIGN, \"=\");\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Make an assignment AST tree\n  tree = mkastnode(A_ASSIGN, left, NULL, right, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including\n// any optional ELSE clause\n// and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement\n// and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement\n// and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, preopAST, NULL, tree, 0));\n}\n\n// Parse a single statement\n// and return its AST\nstatic struct ASTnode *single_statement(void) {\n  switch (Token.token) {\n    case T_PRINT:\n      return (print_statement());\n    case T_INT:\n      var_declaration();\n      return (NULL);\t\t// No AST generated here\n    case T_IDENT:\n      return (assignment_statement());\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_PRINT || tree->op == A_ASSIGN))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "10_For_Loops/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic int Globs = 0;\t\t// Position of next free global symbol slot\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table.\n// Return the slot number in the symbol table\nint addglob(char *name) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  return (y);\n}\n"
  },
  {
    "path": "10_For_Loops/tests/input01",
    "content": "{ print 12 * 3;\n  print 18 - 2 * 4;\n  print 1 + 2 + 9 - 5/2 + 3*5;\n}\n"
  },
  {
    "path": "10_For_Loops/tests/input02",
    "content": "{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  print fred + jim;\n}\n"
  },
  {
    "path": "10_For_Loops/tests/input03",
    "content": "{\n  int x;\n  x= 1;     print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n}\n"
  },
  {
    "path": "10_For_Loops/tests/input04",
    "content": "{\n  int x;\n  x= 7 < 9;  print x;\n  x= 7 <= 9; print x;\n  x= 7 != 9; print x;\n  x= 7 == 7; print x;\n  x= 7 >= 7; print x;\n  x= 7 <= 7; print x;\n  x= 9 > 7;  print x;\n  x= 9 >= 7; print x;\n  x= 9 != 7; print x;\n}\n"
  },
  {
    "path": "10_For_Loops/tests/input05",
    "content": "{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    print i;\n  } else {\n    print j;\n  }\n}\n"
  },
  {
    "path": "10_For_Loops/tests/input06",
    "content": "{ int i;\n  i=1;\n  while (i <= 10) {\n    print i;\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "10_For_Loops/tests/input07",
    "content": "{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n"
  },
  {
    "path": "10_For_Loops/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then\n     ../comp1 $i\n     cc -o out out.s\n     ./out > out.$i\n     rm -f out out.s\n   fi\ndone\n"
  },
  {
    "path": "10_For_Loops/tests/mktestsn",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -o out out.o\n     ./out > out.$i\n     rm -f out out.s\n   fi\ndone\n"
  },
  {
    "path": "10_For_Loops/tests/out.input01",
    "content": "36\n10\n25\n"
  },
  {
    "path": "10_For_Loops/tests/out.input02",
    "content": "17\n"
  },
  {
    "path": "10_For_Loops/tests/out.input03",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "10_For_Loops/tests/out.input04",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "10_For_Loops/tests/out.input05",
    "content": "6\n"
  },
  {
    "path": "10_For_Loops/tests/out.input06",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "10_For_Loops/tests/out.input07",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "10_For_Loops/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "10_For_Loops/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -o out out.o\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "10_For_Loops/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int intvalue) {\n  return (mkastnode(op, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue) {\n  return (mkastnode(op, left, NULL, NULL, intvalue));\n}\n"
  },
  {
    "path": "11_Functions_pt1/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g $(SRCN)\n\nclean:\n\trm -f comp1 compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntest8: comp1 tests/input08\n\t./comp1 tests/input08\n\tcc -o out out.s\n\t./out\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\ntest8n: compn tests/input08\n\t./compn tests/input08\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out out.o\n\t./out\n"
  },
  {
    "path": "11_Functions_pt1/Readme.md",
    "content": "# Part 11: Functions, part 1\n\nI want to start work on implementing functions into our language, but I\nknow this is going to involve a heck of a lot of steps. Some things\nthat we will have to deal with along the way are:\n\n + Types of data: `char`, `int`, `long` etc.\n + The return type of each function\n + The number of arguments to each function\n + Variables local to a function versus global variables\n\nThat is way too much to get done in this part of our journey. So what I'm\ngoing to do here is to get to the point where we can *declare* different\nfunctions. Only the `main()` function in our resulting executable will\nrun, but we will have the ability to generate code for multiple function.\n\nHopefully soon, the language that our compiler recognises will be\nenough of a subset of C that our input will be recognisable by a \"real\" C\ncompiler. But just not yet.\n\n## The Simplistic Function Syntax\n\nThis is definitely going to be a placeholder, so that we can parse\nsomething that looks like a function. Once this is done, we can add\nthose other important things: types, return types, arguments etc.\n\nSo, for now, I will add a function grammar that looks like this in BNF:\n\n```\n function_declaration: 'void' identifier '(' ')' compound_statement   ;\n```\n\nAll functions will be declared `void` and have no arguments. We also won't\nintroduce the ability to call a function, so only the `main()` function\nwill execute.\n\nWe need a new keyword `void` and a new token T_VOID, which are both easy to\nadd.\n\n## Parsing the Simplistic Function Syntax\n\nThe new function syntax is so simple that we can write a nice, small function\nto parse it (in `decl.c`):\n\n```c\n// Parse the declaration of a simplistic function\nstruct ASTnode *function_declaration(void) {\n  struct ASTnode *tree;\n  int nameslot;\n\n  // Find the 'void', the identifier, and the '(' ')'.\n  // For now, do nothing with them\n  match(T_VOID, \"void\");\n  ident();\n  nameslot= addglob(Text);\n  lparen();\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree= compound_statement();\n\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return(mkastunary(A_FUNCTION, tree, nameslot));\n}\n```\n\nThis is going to do the syntax checking and AST building, but there is\nlittle to no semantic error checking here. What if a function gets\nredeclared? Well, we won't notice that yet.\n\n## Modifications to `main()`\n\nWith the above function, we can now rewrite some of the code in `main()`\nto parse multiple functions one after the other:\n\n```c\n  scan(&Token);                 // Get the first token from the input\n  genpreamble();                // Output the preamble\n  while (1) {                   // Parse a function and\n    tree = function_declaration();\n    genAST(tree, NOREG, 0);     // generate the assembly code for it\n    if (Token.token == T_EOF)   // Stop when we have reached EOF\n      break;\n  }\n```\n\nNotice that I've removed the `genpostamble()` function call. That's because\nits output was technically the postamble to the generated assembly for\n`main()`. We now need some code generation functions to generate the\nbeginning of a function and the end of a function.\n\n## Generic Code Generation for Functions\n\nNow that we have an A_FUNCTION AST node, we had better add some code\nin the generic code generator, `gen.c` to deal with it. Looking above,\nthis is a *unary* AST node with a single child:\n\n```c\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return(mkastunary(A_FUNCTION, tree, nameslot));\n```\n\nThe child has the sub-tree which holds the compound statement that\nis the body of the function. We need to generate the start of the\nfunction *before* we generate the code for the compound statement.\nSo here's the code in `genAST()` to do this:\n\n```c\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      cgfuncpreamble(Gsym[n->v.id].name);\n      genAST(n->left, NOREG, n->op);\n      cgfuncpostamble();\n      return (NOREG);\n```\n\n## x86-64 Code Generation\n\nNow we are at the point where we have to generate the code to set the\nstack and frame pointer for each function, and also to undo this at\nthe end of the function and return to the function's caller.\n\nWe already have this code in `cgpreamble()` and `cgpostamble()`, but\n`cgpreamble()` also has the assembly code for the `printint()` function.\nTherefore, it's a matter of separating out these snippets of assembly\ncode into new functions in `cg.c`:\n\n```c\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  // Only prints out the code for printint()\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(char *name) {\n  fprintf(Outfile,\n          \"\\t.text\\n\"\n          \"\\t.globl\\t%s\\n\"\n          \"\\t.type\\t%s, @function\\n\"\n          \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n          \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble() {\n  fputs(\"\\tmovl $0, %eax\\n\" \"\\tpopq     %rbp\\n\" \"\\tret\\n\", Outfile);\n}\n```\n\n## Testing The Function Generation Functionality\n\nWe have a new test program, `tests/input08` which is starting to look\nlike a C program (apart from the `print` statement):\n\n```c\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n```\n\nTo test this, `make test8` which does:\n\n```\ncc -o comp1 -g cg.c decl.c expr.c gen.c main.c misc.c scan.c\n    stmt.c sym.c tree.c\n./comp1 tests/input08\ncc -o out out.s\n./out\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n```\n\nI'm not going to look at the assembly output as it's identical to the\ncode generated for the FOR loop test in the last part.\n\nHowever, I've added `void main()` into all the previous test input files,\nas the language requires a function declaration before the compound\nstatement code.\n\nThe test program `tests/input09` has two functions declared in it.\nThe compiler happily generates working assembly code for each function,\nbut at present we can't run the code for the second function.\n\n## Conclusion and What's Next\n\nWe've made a good start at adding functions to our language. For now,\nit's a pretty simplistic function declaration only.\n\nIn the next part of our compiler writing journey, we will begin\nthe process to add types to our compiler. [Next step](../12_Types_pt1/Readme.md)\n"
  },
  {
    "path": "11_Functions_pt1/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\n// We need a list of byte registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\"\n\t\".LC0:\\n\"\n\t\"\\t.string\\t\\\"%d\\\\n\\\"\\n\"\n\t\"printint:\\n\"\n\t\"\\tpushq\\t%rbp\\n\"\n\t\"\\tmovq\\t%rsp, %rbp\\n\"\n\t\"\\tsubq\\t$16, %rsp\\n\"\n\t\"\\tmovl\\t%edi, -4(%rbp)\\n\"\n\t\"\\tmovl\\t-4(%rbp), %eax\\n\"\n\t\"\\tmovl\\t%eax, %esi\\n\"\n\t\"\\tleaq\t.LC0(%rip), %rdi\\n\"\n\t\"\\tmovl\t$0, %eax\\n\"\n\t\"\\tcall\tprintf@PLT\\n\" \"\\tnop\\n\" \"\\tleave\\n\" \"\\tret\\n\" \"\\n\", Outfile);\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(char *name) {\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble() {\n  fputs(\"\\tmovl\t$0, %eax\\n\" \"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgloadint(int value) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(char *identifier) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", identifier, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, char *identifier) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], identifier);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(char *sym) {\n  fprintf(Outfile, \"\\t.comm\\t%s,8,8\\n\", sym);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n"
  },
  {
    "path": "11_Functions_pt1/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\tglobal\\tmain\\n\"\n\t\"\\textern\\tprintf\\n\"\n\t\"\\tsection\\t.text\\n\"\n\t\"LC0:\\tdb\\t\\\"%d\\\",10,0\\n\"\n\t\"printint:\\n\"\n\t\"\\tpush\\trbp\\n\"\n\t\"\\tmov\\trbp, rsp\\n\"\n\t\"\\tsub\\trsp, 16\\n\"\n\t\"\\tmov\\t[rbp-4], edi\\n\"\n\t\"\\tmov\\teax, [rbp-4]\\n\"\n\t\"\\tmov\\tesi, eax\\n\"\n\t\"\\tlea\trdi, [rel LC0]\\n\"\n\t\"\\tmov\teax, 0\\n\"\n\t\"\\tcall\tprintf\\n\" \"\\tnop\\n\" \"\\tleave\\n\" \"\\tret\\n\" \"\\n\", Outfile);\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(char *name) {\n  fprintf(Outfile,\n\t  \"\\tsection\\t.text\\n\"\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble() {\n  fputs(\"\\tmov\teax, 0\\n\" \"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register\nint cgloadint(int value) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(char *identifier) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], identifier);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, char *identifier) {\n  fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", identifier, reglist[r]);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(char *sym) {\n  fprintf(Outfile, \"\\tcommon\\t%s 8:8\\n\", sym);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n"
  },
  {
    "path": "11_Functions_pt1/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n"
  },
  {
    "path": "11_Functions_pt1/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// variable_declaration: 'int' identifier ';'  ;\n//\n// Parse the declaration of a variable\nvoid var_declaration(void) {\n\n  // Ensure we have an 'int' token followed by an identifier\n  // and a semicolon. Text now has the identifier's name.\n  // Add it as a known identifier\n  match(T_INT, \"int\");\n  ident();\n  addglob(Text);\n  genglobsym(Text);\n  semi();\n}\n\n// For now we have a very simplistic function definition grammar\n//\n// function_declaration: 'void' identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function\nstruct ASTnode *function_declaration(void) {\n  struct ASTnode *tree;\n  int nameslot;\n\n  // Find the 'void', the identifier, and the '(' ')'.\n  // For now, do nothing with them\n  match(T_VOID, \"void\");\n  ident();\n  nameslot= addglob(Text);\n  lparen();\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree= compound_statement();\n\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return(mkastunary(A_FUNCTION, tree, nameslot));\n}\n"
  },
  {
    "path": "11_Functions_pt1/decl.h",
    "content": "\n// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n// scan.c\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int intvalue);\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue);\n\n// gen.c\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\nvoid genglobsym(char *s);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgfuncpreamble(char *name);\nvoid cgfuncpostamble();\nint cgloadint(int value);\nint cgloadglob(char *identifier);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nvoid cgprintint(int r);\nint cgstorglob(int r, char *identifier);\nvoid cgglobsym(char *sym);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name);\n\n// decl.c\nvoid var_declaration(void);\nstruct ASTnode *function_declaration(void);\n"
  },
  {
    "path": "11_Functions_pt1/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_INTLIT, T_SEMI, T_ASSIGN, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  // Keywords\n  T_PRINT, T_INT, T_IF, T_ELSE, T_WHILE,\n  T_FOR, T_VOID\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ADD = 1, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT,\n  A_IDENT, A_LVIDENT, A_ASSIGN, A_PRINT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int id;\t\t\t// For A_IDENT, the symbol slot number\n  } v;\t\t\t\t// For A_FUNCTION, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n};\n"
  },
  {
    "path": "11_Functions_pt1/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      n = mkastleaf(A_INTLIT, Token.intvalue);\n      break;\n\n    case T_IDENT:\n      // Check that this identifier exists\n      id = findglob(Text);\n      if (id == -1)\n\tfatals(\"Unknown variable\", Text);\n\n      // Make a leaf AST node for it\n      n = mkastleaf(A_IDENT, id);\n      break;\n\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into an AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int arithop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_PLUS, T_MINUS\n  20, 20,\t\t\t// T_STAR, T_SLASH\n  30, 30,\t\t\t// T_EQ, T_NE\n  40, 40, 40, 40\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int tokentype;\n\n  // Get the primary tree on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon or ')', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "11_Functions_pt1/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int label(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = label();\n  if (n->right)\n    Lend = label();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOREG, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOREG, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\n// and an optional ELSE clause\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = label();\n  Lend = label();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOREG, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, the register (if any) that holds\n// the previous rvalue, and the AST op of the parent,\n// generate assembly code recursively.\n// Return the register id with the tree's final value\nint genAST(struct ASTnode *n, int reg, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We now have specific AST node handling at the top\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOREG, n->op);\n      genfreeregs();\n      genAST(n->right, NOREG, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      cgfuncpreamble(Gsym[n->v.id].name);\n      genAST(n->left, NOREG, n->op);\n      cgfuncpostamble();\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOREG, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, leftreg, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, reg));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue));\n    case A_IDENT:\n      return (cgloadglob(Gsym[n->v.id].name));\n    case A_LVIDENT:\n      return (cgstorglob(reg, Gsym[n->v.id].name));\n    case A_ASSIGN:\n      // The work has already been done, return the result\n      return (rightreg);\n    case A_PRINT:\n      // Print the left-child's value\n      // and return no register\n      genprintint(leftreg);\n      genfreeregs();\n      return (NOREG);\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\nvoid genglobsym(char *s) {\n  cgglobsym(s);\n}\n"
  },
  {
    "path": "11_Functions_pt1/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nvoid main(int argc, char *argv[]) {\n  struct ASTnode *tree;\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  while (1) {\t\t\t// Parse a function and\n    tree = function_declaration();\n    genAST(tree, NOREG, 0);\t// generate the assembly code for it\n    if (Token.token == T_EOF)\t// Stop when we have reached EOF\n      break;\n  }\n  fclose(Outfile);\t\t// Close the output file and exit\n  exit(0);\n}\n"
  },
  {
    "path": "11_Functions_pt1/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "11_Functions_pt1/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'p':\n      if (!strcmp(s, \"print\"))\n\treturn (T_PRINT);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tfatalc(\"Unrecognised character\", c);\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif (tokentype = keyword(Text)) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "11_Functions_pt1/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: print_statement\n//      |     declaration\n//      |     assignment_statement\n//      |     if_statement\n//      |     while_statement\n//      ;\n\n// print_statement: 'print' expression ';'  ;\n//\nstatic struct ASTnode *print_statement(void) {\n  struct ASTnode *tree;\n  int reg;\n\n  // Match a 'print' as the first token\n  match(T_PRINT, \"print\");\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Make an print AST tree\n  tree = mkastunary(A_PRINT, tree, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// assignment_statement: identifier '=' expression ';'   ;\n//\nstatic struct ASTnode *assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // Check it's been defined then make a leaf node for it\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared variable\", Text);\n  }\n  right = mkastleaf(A_LVIDENT, id);\n\n  // Ensure we have an equals sign\n  match(T_ASSIGN, \"=\");\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Make an assignment AST tree\n  tree = mkastnode(A_ASSIGN, left, NULL, right, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including\n// any optional ELSE clause\n// and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement\n// and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement\n// and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, preopAST, NULL, tree, 0));\n}\n\n// Parse a single statement\n// and return its AST\nstatic struct ASTnode *single_statement(void) {\n  switch (Token.token) {\n    case T_PRINT:\n      return (print_statement());\n    case T_INT:\n      var_declaration();\n      return (NULL);\t\t// No AST generated here\n    case T_IDENT:\n      return (assignment_statement());\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_PRINT || tree->op == A_ASSIGN))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "11_Functions_pt1/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic int Globs = 0;\t\t// Position of next free global symbol slot\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table.\n// Return the slot number in the symbol table\nint addglob(char *name) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  return (y);\n}\n"
  },
  {
    "path": "11_Functions_pt1/tests/input01",
    "content": "void main()\n{ print 12 * 3;\n  print 18 - 2 * 4;\n  print 1 + 2 + 9 - 5/2 + 3*5;\n}\n"
  },
  {
    "path": "11_Functions_pt1/tests/input02",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  print fred + jim;\n}\n"
  },
  {
    "path": "11_Functions_pt1/tests/input03",
    "content": "void main()\n{\n  int x;\n  x= 1;     print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n}\n"
  },
  {
    "path": "11_Functions_pt1/tests/input04",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  print x;\n  x= 7 <= 9; print x;\n  x= 7 != 9; print x;\n  x= 7 == 7; print x;\n  x= 7 >= 7; print x;\n  x= 7 <= 7; print x;\n  x= 9 > 7;  print x;\n  x= 9 >= 7; print x;\n  x= 9 != 7; print x;\n}\n"
  },
  {
    "path": "11_Functions_pt1/tests/input05",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    print i;\n  } else {\n    print j;\n  }\n}\n"
  },
  {
    "path": "11_Functions_pt1/tests/input06",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    print i;\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "11_Functions_pt1/tests/input07",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n"
  },
  {
    "path": "11_Functions_pt1/tests/input08",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n"
  },
  {
    "path": "11_Functions_pt1/tests/input09",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { print 2 * b - a; }\n}\n"
  },
  {
    "path": "11_Functions_pt1/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then\n     ../comp1 $i\n     cc -o out out.s\n     ./out > out.$i\n     rm -f out out.s\n   fi\ndone\n"
  },
  {
    "path": "11_Functions_pt1/tests/mktestsn",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -o out out.o\n     ./out > out.$i\n     rm -f out out.s\n   fi\ndone\n"
  },
  {
    "path": "11_Functions_pt1/tests/out.input01",
    "content": "36\n10\n25\n"
  },
  {
    "path": "11_Functions_pt1/tests/out.input02",
    "content": "17\n"
  },
  {
    "path": "11_Functions_pt1/tests/out.input03",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "11_Functions_pt1/tests/out.input04",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "11_Functions_pt1/tests/out.input05",
    "content": "6\n"
  },
  {
    "path": "11_Functions_pt1/tests/out.input06",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "11_Functions_pt1/tests/out.input07",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "11_Functions_pt1/tests/out.input08",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "11_Functions_pt1/tests/out.input09",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "11_Functions_pt1/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "11_Functions_pt1/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -o out out.o\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "11_Functions_pt1/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int intvalue) {\n  return (mkastnode(op, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, struct ASTnode *left, int intvalue) {\n  return (mkastnode(op, left, NULL, NULL, intvalue));\n}\n"
  },
  {
    "path": "12_Types_pt1/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c types.c\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c types.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g $(SRCN)\n\nclean:\n\trm -f comp1 compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntest10: comp1 tests/input10\n\t./comp1 tests/input10\n\tcc -o out out.s\n\t./out\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\ntest10n: compn tests/input10\n\t./compn tests/input10\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out out.o\n\t./out\n"
  },
  {
    "path": "12_Types_pt1/Readme.md",
    "content": "# Part 12: Types, part 1\n\nI've just begun the process to add types to our compiler. Now, I should\nwarn you that this is new to me, as in my\n[previous compiler](https://github.com/DoctorWkt/h-compiler) I only had\n`int`s. I've resisted the urge to look at the SubC source code for ideas.\nThus, I'm striking out on my own and it's likely that I will have to redo\nsome of the code as I deal with the greater issues involving types.\n\n## What Types for Now?\n\nI'll start with `char` and `int` for our global variables. We've already\nadded the `void` keyword for functions. In the next step I will add\nfunction return values. So, for now, `void` exists but I'm not fully\ndealing with it.\n\nObviously, `char` has a much more limited range of values that `int`.\nLike SubC, I'm going to use the range 0 .. 255 for `char`s and\na range of signed values for `int`s.\n\nThis means that we can widen `char` values to become `int`s, but we\nmust warn the developer if they try to narrow `int` values down to a\n`char` range.\n\n## New Keywords and Tokens\n\nThere is only the new 'char' keyword and the T_CHAR token. Nothing\nexciting here.\n\n## Expression Types\n\nFrom now on, every expression has a type. This includes:\n\n + integer literals, e.g 56 is an `int`\n + maths expressions, e.g. 45 - 12 is an `int`\n + variables, e.g. if we declared `x` as a `char`, then\n   it's *rvalue* is a `char`\n\nWe are going to have to track the type of each expression as we evaluate\nit, to ensure we can widen it as required or refuse to narrow it if\nnecessary.\n\nIn the SubC compiler, Nils created a single *lvalue* structure. A pointer\nto this single stucture was passed around in the recursive parser to\ntrack the type of any expression at a point in its parsing.\n\nI've taken a different tack. I've modified our Abstract Syntax Tree node\nto have a `type` field which holds the type of the tree at that point.\nIn `defs.h`, here are the types I've created so far:\n\n```c\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT\n};\n```\n\nI've called them *primitive* types, as Nils did in SubC, because I can't\nthink of a better name for them. Data types, perhaps? The P_NONE value\nindicates that the AST node *doesn't* represent an expression and has no\ntype. An example is the A_GLUE node type which glues statements together:\nonce the left-hand statement is generated, there is no type to speak of.\n\nIf you look in `tree.c`, you will see that the functions to build AST\nnodes have been modified to also assign to the `type` field in the new\nAST node structure (in `defs.h`):\n\n```c\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  ...\n};\n```\n\n## Variable Declarations and Their Types\n\nWe now have at least two ways to declare global variables:\n\n```c\n  int x; char y;\n```\n\nWe'll need to parse this, yes. But first, how do we record the type for\neach variable? We need to modify the `symtable` structure. I've also added \nthe details of the \"structural type\" of the symbol which I'll use in the\nfuture (in `defs.h`):\n\n```c\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  int stype;                    // Structural type for the symbol\n};\n```\n\nThere's new code in `newglob()` in `sym.c` to initialise these new\nfields:\n\n```c\nint addglob(char *name, int type, int stype) {\n  ...\n  Gsym[y].type = type;\n  Gsym[y].stype = stype;\n  return (y);\n}\n```\n\n## Parsing Variable Declarations\n\nIt's time to separate out the parsing of the type from the parsing\nof the variable itself. So, in `decl.c` we now have:\n\n```c\n// Parse the current token and\n// return a primitive type enum value\nint parse_type(int t) {\n  if (t == T_CHAR) return (P_CHAR);\n  if (t == T_INT)  return (P_INT);\n  if (t == T_VOID) return (P_VOID);\n  fatald(\"Illegal type, token\", t);\n}\n\n// Parse the declaration of a variable\nvoid var_declaration(void) {\n  int id, type;\n\n  // Get the type of the variable, then the identifier\n  type = parse_type(Token.token);\n  scan(&Token);\n  ident();\n  id = addglob(Text, type, S_VARIABLE);\n  genglobsym(id);\n  semi();\n}\n```\n\n## Dealing with Expression Types\n\nAll of the above is the easy part done! We now have:\n\n  + a set of three types: `char`, `int` and `void`,\n  + parsing of variable declarations to find their type,\n  + capture of each variable's type in the symbol table, and\n  + storage of the type of an expression in each AST node\n\nNow we need to actually fill in the type in the AST nodes that\nwe build. Then we have to decide when to widen types and/or\nreject type clashes. Let's get on with the job!\n\n## Parsing Primary Terminals\n\nWe'll start with the parsing of integer literal values and\nvariable identifiers. One wrinkle is that we want to be able to do:\n\n```c\n  char j; j= 2;\n```\n\nBut if we mark the `2` as a P_INT, then we won't be able to narrow\nthe value when we try to store it in the P_CHAR `j` variable. For\nnow, I've added some semantic code to keep small integer literal\nvalues as P_CHARs:\n\n```c\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n        n = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n      else\n        n = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n      break;\n\n    case T_IDENT:\n      // Check that this identifier exists\n      id = findglob(Text);\n      if (id == -1)\n        fatals(\"Unknown variable\", Text);\n\n      // Make a leaf AST node for it\n      n = mkastleaf(A_IDENT, Gsym[id].type, id);\n      break;\n\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n```\n\nAlso note that, for identifiers, we can easily get their type\ndetails from the global symbol table.\n\n## Building Binary Expressions: Comparing Types\n\nAs we build maths expressions with our binary maths operators, we\nwill have a type from the left-hand child and a type from the right-hand\nchild. Here is where we are going to have to either widen, do nothing, or\nreject the expression if the two types are incompatible.\n\nFor now, I have a new file `types.c` with a function that compares\nthe types on either side. Here's the code:\n\n```c\n// Given two primitive types, return true if they are compatible,\n// false otherwise. Also return either zero or an A_WIDEN\n// operation if one has to be widened to match the other.\n// If onlyright is true, only widen left to right.\nint type_compatible(int *left, int *right, int onlyright) {\n\n  // Voids not compatible with anything\n  if ((*left == P_VOID) || (*right == P_VOID)) return (0);\n\n  // Same types, they are compatible\n  if (*left == *right) { *left = *right = 0; return (1);\n  }\n\n  // Widen P_CHARs to P_INTs as required\n  if ((*left == P_CHAR) && (*right == P_INT)) {\n    *left = A_WIDEN; *right = 0; return (1);\n  }\n  if ((*left == P_INT) && (*right == P_CHAR)) {\n    if (onlyright) return (0);\n    *left = 0; *right = A_WIDEN; return (1);\n  }\n  // Anything remaining is compatible\n  *left = *right = 0;\n  return (1);\n}\n```\n\nThere's a fair bit going on here. Firstly, if both types are the same\nwe can simply return True. Anything with a P_VOID cannot be mixed\nwith another type.\n\nIf one side is a P_CHAR and the other is a P_INT, we can widen the\nresult to a P_INT. The way I do this is to modify the type information\nthat comes in and I replace it either with zero (do nothing), or a new\nAST node type A_WIDEN. This means: widen the more narrow child's value\nto be as wide as the wider child's value. We'll see this in operation soon.\n\nThere is one extra argument `onlyright`. I use this when we get to\nA_ASSIGN AST nodes where we are assigning the left-child's expression\nto the variable *lvalue* on the right. If this is set, don't let a\nP_INT expression be transferred to a P_CHAR variable\n\nFinally, for now, let any other type pairs through.\n\nI think I can guarantee that this will need to be changed once we\nbring in arrays and pointers. I also hope I can find a way to make\nthe code simpler and more elegant. But it will do for now.\n\n## Using `type_compatible()` in Expressions\n\nI've used `type_compatible()` in three different places in this version\nof the compiler. We'll start with merging expressions with binary operators.\nI've modified the code in `binexpr()` in `expr.c` to do this:\n\n```c\n    // Ensure the two types are compatible.\n    lefttype = left->type;\n    righttype = right->type;\n    if (!type_compatible(&lefttype, &righttype, 0))\n      fatal(\"Incompatible types\");\n\n    // Widen either side if required. type vars are A_WIDEN now\n    if (lefttype)\n      left = mkastunary(lefttype, right->type, left, 0);\n    if (righttype)\n      right = mkastunary(righttype, left->type, right, 0);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left->type, left, NULL, right, 0);\n```\n\nWe reject incompatible types. But, if `type_compatible()` returned\nnon-zero `lefttype` or `righttype` values, these are actually the\nA_WIDEN value. We can use this to build a unary AST node with the\nnarrow child as the child. When we get to the code generator, it will\nnow know that this child's value has to be widened.\n\nNow, where else do we need to widen expression values?\n\n## Using `type_compatible()` to Print Expressions\n\nWhen we use the `print` keyword, we need to have an `int` expression\nfor it to print. So we need to change `print_statement()` in `stmt.c`:\n\n```c\nstatic struct ASTnode *print_statement(void) {\n  struct ASTnode *tree;\n  int lefttype, righttype;\n  int reg;\n\n  ...\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure the two types are compatible.\n  lefttype = P_INT; righttype = tree->type;\n  if (!type_compatible(&lefttype, &righttype, 0))\n    fatal(\"Incompatible types\");\n\n  // Widen the tree if required. \n  if (righttype) tree = mkastunary(righttype, P_INT, tree, 0);\n```\n\n## Using `type_compatible()` to Assign to a Variable\n\nThis is the last place where we need to check types. When we assign to\na variable, we need to ensure that we can widen the right-hand side\nexpression. We've got to reject any attempt to store a wide type into\na narrow variable. Here is the new code in `assignment_statement()` in\n`stmt.c`:\n\n```c\nstatic struct ASTnode *assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int lefttype, righttype;\n  int id;\n\n  ...\n  // Make an lvalue node for the variable\n  right = mkastleaf(A_LVIDENT, Gsym[id].type, id);\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Ensure the two types are compatible.\n  lefttype = left->type;\n  righttype = right->type;\n  if (!type_compatible(&lefttype, &righttype, 1))  // Note the 1\n    fatal(\"Incompatible types\");\n\n  // Widen the left if required.\n  if (lefttype)\n    left = mkastunary(lefttype, right->type, left, 0);\n```\n\nNote the 1 at the the end to this call to `type_compatible()`.\nThis enforces the semantics that we cannot save a wide value to\na narrow variable.\n\nGiven all of the above, we now can parse a few types and enforce\nsome sensible language semantics: widen values where possible,\nprevent type narrowing and prevent unsuitable type clashes. Now\nwe move to the code generation side of things.\n\n## The Changes to x86-64 Code Geneneration\n\nOur assembly output is register based and essentially they are fixed\nin size. What we can influence is:\n\n + the size of the memory locations to store variables, and\n + how much of a register is used hold data, e.g. one byte for\n   characters, eight bytes for a 64-bit integer.\n\nI'll start with the x86-64 specific code in `cg.c`, and then I'll show how\nthis is used in the generic code generator in `gen.c`.\n\nLet's start with generating the storage for variables.\n\n```c\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  // Choose P_INT or P_CHAR\n  if (Gsym[id].type == P_INT)\n    fprintf(Outfile, \"\\t.comm\\t%s,8,8\\n\", Gsym[id].name);\n  else\n    fprintf(Outfile, \"\\t.comm\\t%s,1,1\\n\", Gsym[id].name);\n}\n```\n\nWe extract the type from the variable slot in the symbol table and choose\nto allocate 1 or 8 bytes for it depending on this type. Now we need to\nload the value into a register:\n\n```c\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it: P_CHAR or P_INT\n  if (Gsym[id].type == P_INT)\n    fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tmovzbq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n  return (r);\n```\n\nThe `movq` instruction moves eight bytes into the 8-byte register. The `movzbq`\ninstruction zeroes the 8-byte register and then moves a single byte into it.\nThis also implicitly widens the one byte value to eight bytes. Our storage\nfunction is similar:\n\n```c\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  // Choose P_INT or P_CHAR\n  if (Gsym[id].type == P_INT)\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], Gsym[id].name);\n  else\n    fprintf(Outfile, \"\\tmovb\\t%s, %s(\\%%rip)\\n\", breglist[r], Gsym[id].name);\n  return (r);\n}\n```\n\nThis time we have to use the \"byte\" name of the register and the `movb`\ninstruction to move a single byte.\n\nLuckily, the `cgloadglob()` function has already done the widening of\nP_CHAR variables. So this is the code for our new `cgwiden()` function:\n\n```c\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n```\n## The Changes to The Generic Code Geneneration\n\nWith the above in place, there are only a few changes to the generic\ncode generator in `gen.c`:\n\n  + The calls to `cgloadglob()` and `cgstorglob()` now take the\n    symbol's slot number and not the symbol's name.\n  + Similarly, `genglobsym()` now receives the symbol's slot number and\n    passes it on to `cgglobsym()`\n\nThe only major change is the code to deal with the new A_WIDEN AST node type.\nWe don't need this node (as `cgwiden()` does nothing), but it's here for\nother hardware platforms:\n\n```c\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n```\n\n## Testing the New Type Changes\n\nHere is my test input file, `tests/input10`:\n\n```c\nvoid main()\n{\n  int i; char j;\n\n  j= 20; print j;\n  i= 10; print i;\n\n  for (i= 1;   i <= 5; i= i + 1) { print i; }\n  for (j= 253; j != 2; j= j + 1) { print j; }\n}\n```\n\nI check that we can assign to and print from `char` and `int` types.\nI also verify that, for `char` variables, we will overflow in the\nvalue sequence: 253, 254, 255, 0, 1, 2 etc.\n\n```\n$ make test\ncc -o comp1 -g cg.c decl.c expr.c gen.c main.c misc.c scan.c\n   stmt.c sym.c tree.c types.c\n./comp1 tests/input10\ncc -o out out.s\n./out\n20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n```\n\nLet's look at some of the assembly that was generated:\n\n```\n        .comm   i,8,8                   # Eight byte i storage\n        .comm   j,1,1                   # One   byte j storage\n        ...\n        movq    $20, %r8\n        movb    %r8b, j(%rip)           # j= 20\n        movzbq  j(%rip), %r8\n        movq    %r8, %rdi               # print j\n        call    printint\n\n        movq    $253, %r8\n        movb    %r8b, j(%rip)           # j= 253\nL3:\n        movzbq  j(%rip), %r8\n        movq    $2, %r9\n        cmpq    %r9, %r8                # while j != 2\n        je      L4\n        movzbq  j(%rip), %r8\n        movq    %r8, %rdi               # print j\n        call    printint\n        movzbq  j(%rip), %r8\n        movq    $1, %r9                 # j= j + 1\n        addq    %r8, %r9\n        movb    %r9b, j(%rip)\n        jmp     L3\n```\n\nStill not the most elegant assembly code, but it does work. Also,\n`$ make test` confirms that all the previous code examples still work.\n\n## Conclusion and What's Next\n\nIn the next part of our compiler writing journey, we will\nadd function calls with one argument, and returning a value\nfrom  a function. [Next step](../13_Functions_pt2/Readme.md)\n"
  },
  {
    "path": "12_Types_pt1/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\n// We need a list of byte registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\"\n\t\".LC0:\\n\"\n\t\"\\t.string\\t\\\"%d\\\\n\\\"\\n\"\n\t\"printint:\\n\"\n\t\"\\tpushq\\t%rbp\\n\"\n\t\"\\tmovq\\t%rsp, %rbp\\n\"\n\t\"\\tsubq\\t$16, %rsp\\n\"\n\t\"\\tmovl\\t%edi, -4(%rbp)\\n\"\n\t\"\\tmovl\\t-4(%rbp), %eax\\n\"\n\t\"\\tmovl\\t%eax, %esi\\n\"\n\t\"\\tleaq\t.LC0(%rip), %rdi\\n\"\n\t\"\\tmovl\t$0, %eax\\n\"\n\t\"\\tcall\tprintf@PLT\\n\" \"\\tnop\\n\" \"\\tleave\\n\" \"\\tret\\n\" \"\\n\", Outfile);\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(char *name) {\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble() {\n  fputs(\"\\tmovl\t$0, %eax\\n\" \"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it: P_CHAR or P_INT\n  if (Gsym[id].type == P_INT)\n    fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tmovzbq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  // Choose P_INT or P_CHAR\n  if (Gsym[id].type == P_INT)\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], Gsym[id].name);\n  else\n    fprintf(Outfile, \"\\tmovb\\t%s, %s(\\%%rip)\\n\", breglist[r], Gsym[id].name);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  // Choose P_INT or P_CHAR\n  if (Gsym[id].type == P_INT)\n    fprintf(Outfile, \"\\t.comm\\t%s,8,8\\n\", Gsym[id].name);\n  else\n    fprintf(Outfile, \"\\t.comm\\t%s,1,1\\n\", Gsym[id].name);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n"
  },
  {
    "path": "12_Types_pt1/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\tglobal\\tmain\\n\"\n\t\"\\textern\\tprintf\\n\"\n\t\"\\tsection\\t.text\\n\"\n\t\"LC0:\\tdb\\t\\\"%d\\\",10,0\\n\"\n\t\"printint:\\n\"\n\t\"\\tpush\\trbp\\n\"\n\t\"\\tmov\\trbp, rsp\\n\"\n\t\"\\tsub\\trsp, 16\\n\"\n\t\"\\tmov\\t[rbp-4], edi\\n\"\n\t\"\\tmov\\teax, [rbp-4]\\n\"\n\t\"\\tmov\\tesi, eax\\n\"\n\t\"\\tlea\trdi, [rel LC0]\\n\"\n\t\"\\tmov\teax, 0\\n\"\n\t\"\\tcall\tprintf\\n\" \"\\tnop\\n\" \"\\tleave\\n\" \"\\tret\\n\" \"\\n\", Outfile);\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(char *name) {\n  fprintf(Outfile,\n\t  \"\\tsection\\t.text\\n\"\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble() {\n  fputs(\"\\tmov\teax, 0\\n\" \"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it: P_CHAR or P_INT\n  if (Gsym[id].type == P_INT)\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Gsym[id].name);\n  else\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], Gsym[id].name);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  // Choose P_INT or P_CHAR\n  if (Gsym[id].type == P_INT)\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, breglist[r]);\n  return (r);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  // Choose P_INT or P_CHAR\n  if (Gsym[id].type == P_INT)\n    fprintf(Outfile, \"\\tcommon\\t%s 8:8\\n\", Gsym[id].name);\n  else\n    fprintf(Outfile, \"\\tcommon\\t%s 1:1\\n\", Gsym[id].name);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n"
  },
  {
    "path": "12_Types_pt1/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n"
  },
  {
    "path": "12_Types_pt1/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and\n// return a primitive type enum value\nint parse_type(int t) {\n  if (t == T_CHAR)\n    return (P_CHAR);\n  if (t == T_INT)\n    return (P_INT);\n  if (t == T_VOID)\n    return (P_VOID);\n  fatald(\"Illegal type, token\", t);\n}\n\n// variable_declaration: 'int' identifier ';'  ;\n//\n// Parse the declaration of a variable\nvoid var_declaration(void) {\n  int id, type;\n\n  // Get the type of the variable, then the identifier\n  type = parse_type(Token.token);\n  scan(&Token);\n  ident();\n  // Text now has the identifier's name.\n  // Add it as a known identifier\n  // and generate its space in assembly\n  id = addglob(Text, type, S_VARIABLE);\n  genglobsym(id);\n  // Get the trailing semicolon\n  semi();\n}\n\n// For now we have a very simplistic function definition grammar\n//\n// function_declaration: 'void' identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function\nstruct ASTnode *function_declaration(void) {\n  struct ASTnode *tree;\n  int nameslot;\n\n  // Find the 'void', the identifier, and the '(' ')'.\n  // For now, do nothing with them\n  match(T_VOID, \"void\");\n  ident();\n  nameslot = addglob(Text, P_VOID, S_FUNCTION);\n  lparen();\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, P_VOID, tree, nameslot));\n}\n"
  },
  {
    "path": "12_Types_pt1/decl.h",
    "content": "\n// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n// scan.c\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\n\n// gen.c\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\nvoid genglobsym(int id);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgfuncpreamble(char *name);\nvoid cgfuncpostamble();\nint cgloadint(int value, int type);\nint cgloadglob(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nvoid cgprintint(int r);\nint cgstorglob(int r, int id);\nvoid cgglobsym(int id);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name, int type, int stype);\n\n// decl.c\nvoid var_declaration(void);\nstruct ASTnode *function_declaration(void);\n\n// types.c\nint type_compatible(int *left, int *right, int onlyright);\n"
  },
  {
    "path": "12_Types_pt1/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_INTLIT, T_SEMI, T_ASSIGN, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  // Keywords\n  T_PRINT, T_INT, T_IF, T_ELSE, T_WHILE,\n  T_FOR, T_VOID, T_CHAR\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ADD = 1, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT,\n  A_IDENT, A_LVIDENT, A_ASSIGN, A_PRINT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int id;\t\t\t// For A_IDENT, the symbol slot number\n  } v;\t\t\t\t// For A_FUNCTION, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n};\n"
  },
  {
    "path": "12_Types_pt1/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n\tn = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n      break;\n\n    case T_IDENT:\n      // Check that this identifier exists\n      id = findglob(Text);\n      if (id == -1)\n\tfatals(\"Unknown variable\", Text);\n\n      // Make a leaf AST node for it\n      n = mkastleaf(A_IDENT, Gsym[id].type, id);\n      break;\n\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into an AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int arithop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_PLUS, T_MINUS\n  20, 20,\t\t\t// T_STAR, T_SLASH\n  30, 30,\t\t\t// T_EQ, T_NE\n  40, 40, 40, 40\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int lefttype, righttype;\n  int tokentype;\n\n  // Get the primary tree on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Ensure the two types are compatible.\n    lefttype = left->type;\n    righttype = right->type;\n    if (!type_compatible(&lefttype, &righttype, 0))\n      fatal(\"Incompatible types\");\n\n    // Widen either side if required. type vars are A_WIDEN now\n    if (lefttype)\n      left = mkastunary(lefttype, right->type, left, 0);\n    if (righttype)\n      right = mkastunary(righttype, left->type, right, 0);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon or ')', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "12_Types_pt1/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int label(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = label();\n  if (n->right)\n    Lend = label();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOREG, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOREG, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\n// and an optional ELSE clause\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = label();\n  Lend = label();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOREG, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, the register (if any) that holds\n// the previous rvalue, and the AST op of the parent,\n// generate assembly code recursively.\n// Return the register id with the tree's final value\nint genAST(struct ASTnode *n, int reg, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We now have specific AST node handling at the top\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOREG, n->op);\n      genfreeregs();\n      genAST(n->right, NOREG, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      cgfuncpreamble(Gsym[n->v.id].name);\n      genAST(n->left, NOREG, n->op);\n      cgfuncpostamble();\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOREG, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, leftreg, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, reg));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue, n->type));\n    case A_IDENT:\n      return (cgloadglob(n->v.id));\n    case A_LVIDENT:\n      return (cgstorglob(reg, n->v.id));\n    case A_ASSIGN:\n      // The work has already been done, return the result\n      return (rightreg);\n    case A_PRINT:\n      // Print the left-child's value\n      // and return no register\n      genprintint(leftreg);\n      genfreeregs();\n      return (NOREG);\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\n"
  },
  {
    "path": "12_Types_pt1/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nvoid main(int argc, char *argv[]) {\n  struct ASTnode *tree;\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  while (1) {\t\t\t// Parse a function and\n    tree = function_declaration();\n    genAST(tree, NOREG, 0);\t// generate the assembly code for it\n    if (Token.token == T_EOF)\t// Stop when we have reached EOF\n      break;\n  }\n  fclose(Outfile);\t\t// Close the output file and exit\n  exit(0);\n}\n"
  },
  {
    "path": "12_Types_pt1/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "12_Types_pt1/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'p':\n      if (!strcmp(s, \"print\"))\n\treturn (T_PRINT);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tfatalc(\"Unrecognised character\", c);\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif (tokentype = keyword(Text)) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "12_Types_pt1/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: print_statement\n//      |     declaration\n//      |     assignment_statement\n//      |     if_statement\n//      |     while_statement\n//      ;\n\n// print_statement: 'print' expression ';'  ;\n//\nstatic struct ASTnode *print_statement(void) {\n  struct ASTnode *tree;\n  int lefttype, righttype;\n  int reg;\n\n  // Match a 'print' as the first token\n  match(T_PRINT, \"print\");\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure the two types are compatible.\n  lefttype = P_INT;\n  righttype = tree->type;\n  if (!type_compatible(&lefttype, &righttype, 0))\n    fatal(\"Incompatible types\");\n\n  // Widen the tree if required. \n  if (righttype)\n    tree = mkastunary(righttype, P_INT, tree, 0);\n\n  // Make an print AST tree\n  tree = mkastunary(A_PRINT, P_NONE, tree, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// assignment_statement: identifier '=' expression ';'   ;\n//\nstatic struct ASTnode *assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int lefttype, righttype;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // Check it's been defined then make a leaf node for it\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared variable\", Text);\n  }\n  right = mkastleaf(A_LVIDENT, Gsym[id].type, id);\n\n  // Ensure we have an equals sign\n  match(T_ASSIGN, \"=\");\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Ensure the two types are compatible.\n  lefttype = left->type;\n  righttype = right->type;\n  if (!type_compatible(&lefttype, &righttype, 1))\n    fatal(\"Incompatible types\");\n\n  // Widen the left if required.\n  if (lefttype)\n    left = mkastunary(lefttype, right->type, left, 0);\n\n  // Make an assignment AST tree\n  tree = mkastnode(A_ASSIGN, P_INT, left, NULL, right, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including\n// any optional ELSE clause\n// and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement\n// and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement\n// and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// Parse a single statement\n// and return its AST\nstatic struct ASTnode *single_statement(void) {\n  switch (Token.token) {\n    case T_PRINT:\n      return (print_statement());\n    case T_CHAR:\n    case T_INT:\n      var_declaration();\n      return (NULL);\t\t// No AST generated here\n    case T_IDENT:\n      return (assignment_statement());\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_PRINT || tree->op == A_ASSIGN))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "12_Types_pt1/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic int Globs = 0;\t\t// Position of next free global symbol slot\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table.\n// Also set up its type and structural type.\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  Gsym[y].type = type;\n  Gsym[y].stype = stype;\n  return (y);\n}\n"
  },
  {
    "path": "12_Types_pt1/tests/input01",
    "content": "void main()\n{ print 12 * 3;\n  print 18 - 2 * 4;\n  print 1 + 2 + 9 - 5/2 + 3*5;\n}\n"
  },
  {
    "path": "12_Types_pt1/tests/input02",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  print fred + jim;\n}\n"
  },
  {
    "path": "12_Types_pt1/tests/input03",
    "content": "void main()\n{\n  int x;\n  x= 1;     print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n}\n"
  },
  {
    "path": "12_Types_pt1/tests/input04",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  print x;\n  x= 7 <= 9; print x;\n  x= 7 != 9; print x;\n  x= 7 == 7; print x;\n  x= 7 >= 7; print x;\n  x= 7 <= 7; print x;\n  x= 9 > 7;  print x;\n  x= 9 >= 7; print x;\n  x= 9 != 7; print x;\n}\n"
  },
  {
    "path": "12_Types_pt1/tests/input05",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    print i;\n  } else {\n    print j;\n  }\n}\n"
  },
  {
    "path": "12_Types_pt1/tests/input06",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    print i;\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "12_Types_pt1/tests/input07",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n"
  },
  {
    "path": "12_Types_pt1/tests/input08",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n"
  },
  {
    "path": "12_Types_pt1/tests/input09",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { print 2 * b - a; }\n}\n"
  },
  {
    "path": "12_Types_pt1/tests/input10",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; print j;\n  i= 10; print i;\n\n  for (i= 1;   i <= 5; i= i + 1) { print i; }\n  for (j= 253; j != 2; j= j + 1) { print j; }\n}\n"
  },
  {
    "path": "12_Types_pt1/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then\n     ../comp1 $i\n     cc -o out out.s\n     ./out > out.$i\n     rm -f out out.s\n   fi\ndone\n"
  },
  {
    "path": "12_Types_pt1/tests/mktestsn",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -o out out.o\n     ./out > out.$i\n     rm -f out out.s\n   fi\ndone\n"
  },
  {
    "path": "12_Types_pt1/tests/out.input01",
    "content": "36\n10\n25\n"
  },
  {
    "path": "12_Types_pt1/tests/out.input02",
    "content": "17\n"
  },
  {
    "path": "12_Types_pt1/tests/out.input03",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "12_Types_pt1/tests/out.input04",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "12_Types_pt1/tests/out.input05",
    "content": "6\n"
  },
  {
    "path": "12_Types_pt1/tests/out.input06",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "12_Types_pt1/tests/out.input07",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "12_Types_pt1/tests/out.input08",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "12_Types_pt1/tests/out.input09",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "12_Types_pt1/tests/out.input10",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "12_Types_pt1/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "12_Types_pt1/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -o out out.o\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "12_Types_pt1/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n"
  },
  {
    "path": "12_Types_pt1/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given two primitive types,\n// return true if they are compatible,\n// false otherwise. Also return either\n// zero or an A_WIDEN operation if one\n// has to be widened to match the other.\n// If onlyright is true, only widen left to right.\nint type_compatible(int *left, int *right, int onlyright) {\n\n  // Voids not compatible with anything\n  if ((*left == P_VOID) || (*right == P_VOID))\n    return (0);\n\n  // Same types, they are compatible\n  if (*left == *right) {\n    *left = *right = 0;\n    return (1);\n  }\n\n  // Widen P_CHARs to P_INTs as required\n  if ((*left == P_CHAR) && (*right == P_INT)) {\n    *left = A_WIDEN;\n    *right = 0;\n    return (1);\n  }\n  if ((*left == P_INT) && (*right == P_CHAR)) {\n    if (onlyright)\n      return (0);\n    *left = 0;\n    *right = A_WIDEN;\n    return (1);\n  }\n  // Anything remaining is compatible\n  *left = *right = 0;\n  return (1);\n}\n"
  },
  {
    "path": "13_Functions_pt2/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c types.c\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c sym.c tree.c types.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g $(SRCN)\n\nclean:\n\trm -f comp1 compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntest14: comp1 tests/input14 lib/printint.c\n\t./comp1 tests/input14\n\tcc -o out out.s lib/printint.c\n\t./out\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\ntest14n: compn tests/input14 lib/printint.c\n\t./compn tests/input14\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out lib/printint.c out.o\n\t./out\n"
  },
  {
    "path": "13_Functions_pt2/Readme.md",
    "content": "# Part 13: Functions, part 2\n\nIn this part of our compiler writing journey, I want to add the ability to\ncall functions and return a value. Specifically:\n\n + define a function, which we already have,\n + call a function with a single value which for now cannot be used,\n + return a value from a function, \n + use a function call as both a statement and also an expression, and\n + ensure that void functions never return a value and non-void\n   functions must return a value.\n\nI've just got this working. I found that I spent most of my time dealing\nwith types. So, on with the writeup.\n\n## New Keywords and Tokens\n\nI've been using 8-byte (64-bit) `int`s in the compiler so far, but I've\nrealised that Gcc treats `int`s as four bytes (32 bits) wide. Therefore,\nI've decided to introduce the `long` type. So now:\n\n  + `char` is one byte wide\n  + `int` is four bytes (32 bits) wide\n  + `long` is eight bytes (64 bits) wide\n\nWe also need the ability to 'return', so we have new keywords 'long'\nand 'return', and associated tokens T_LONG and T_RETURN.\n\n## Parsing Function Calls\n\nFor now, the BNF syntax that I'm using for a function call is:\n\n```\n  function_call: identifier '(' expression ')'   ;\n```\n\nThe function has a name followed by a pair of parentheses. Inside the\nparentheses we must have exactly one argument. I want this to be used\nas both an expression and also as a standalone statement.\n\nSo we'll start with the function call parser,\n`funccall()` in `expr.c`. When we get called, the identifier\nhas already been scanned in and the function's name is in the `Text`\nglobal variable:\n\n```c\n// Parse a function call with a single expression\n// argument and return its AST\nstruct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined,\n  // then make a leaf node for it. XXX Add structural type test\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Gsym[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n```\n\nI've left a reminder comment: *Add structural type test*. When a function\nor a variable is declared, the symbol table is marked with the structural\ntype S_FUNCTION and S_VARIABLE, respectively. I should add code here to\nconfirm the identifier is really an S_FUNCTION.\n\nWe build a new unary AST node, A_FUNCCALL. The child is the single\nexpression to pass as the argument. We store the function's symbol-id\nin the node, and we also record the function's return type.\n\n## But I Don't Want That Token Any More!\n\nThere is a parsing problem. We have to distinguish between:\n\n```\n   x= fred + jim;\n   x= fred(5) + jim;\n```\n\nWe need to look ahead one token to see if there is a '('. If there is,\nwe have a function call. But by doing so, we lose the existing token.\nTo solve this problem, I've modified the scanner so that we can put\nback an unwanted token: this will be returned when we get the next token\ninstead of a brand-new token. The new code in `scan.c` is:\n\n```c\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n\n  // Continue on with the normal scanning\n  ...\n}\n```\n\n## Calling a Function as an Expression\n\nSo now we can look at where, in `expr.c` we need to differentiate\nbetween a variable name and a function call: it's in `primary()`.\nThe new code is:\n\n```c\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    ...\n    case T_IDENT:\n      // This could be a variable or a function call.\n      // Scan in the next token to find out\n      scan(&Token);\n\n      // It's a '(', so a function call\n      if (Token.token == T_LPAREN)\n        return (funccall());\n\n      // Not a function call, so reject the new token\n      reject_token(&Token);\n\n      // Continue on with normal variable parsing\n      ...\n}\n```\n\n## Calling a Function as a Statement\n\nWe have essentially the same problem when we try to call a function as a\nstatement. Here, we have to distinguish between:\n\n```\n  fred = 2;\n  fred(18);\n```\n\nThus, the new statement code in `stmt.c` is similar to the above:\n\n```c\n// Parse an assignment statement and return its AST\nstatic struct ASTnode *assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int lefttype, righttype;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // This could be a variable or a function call.\n  // If next token is '(', it's a function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // Not a function call, on with an assignment then!\n  ...\n}\n```\n\nWe can get away with not rejecting the \"unwanted\" token here, because there\n*has* to be either an '=' or a '(' next: we can write the parser code knowing\nthis is true.\n\n## Parsing a Return Statement\n\nIn BNF, our return statement looks like:\n\n```\n  return_statement: 'return' '(' expression ')'  ;\n```\n\nThe parsing is easy: 'return', '(', call `binexpr()`, ')', done! What is more\ndifficult is the checking of the type, and if we even should be allowed to\nreturn at all.\n\nSomehow we need to know which function we are actually in, when we get to\na return statement. I've added a global variable in `data.h`:\n\n```c\nextern_ int Functionid;         // Symbol id of the current function\n```\n\nand this is set up in `function_declaration()` in `decl.c`:\n\n```c\nstruct ASTnode *function_declaration(void) {\n  ...\n  // Add the function to the symbol table\n  // and set the Functionid global\n  nameslot = addglob(Text, type, S_FUNCTION, endlabel);\n  Functionid = nameslot;\n  ...\n}\n```\n\nWith `Functionid` set up each time we enter a function declaration, we\ncan get back to parsing and checking the semantics of a return statement.\nThe new code is `return_statement()` in `stmt.c`:\n\n```c\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n  int returntype, functype;\n\n  // Can't return a value if function returns P_VOID\n  if (Gsym[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  returntype = tree->type;\n  functype = Gsym[Functionid].type;\n  if (!type_compatible(&returntype, &functype, 1))\n    fatal(\"Incompatible types\");\n\n  // Widen the left if required.\n  if (returntype)\n    tree = mkastunary(returntype, functype, tree, 0);\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n```\n\nWe have a new A_RETURN AST node that returns the expression in the child\ntree. We use `type_compatible()` to ensure the expression matches the\nreturn type, and widen it if required.\n\nFinally, we see if the function was actually declared `void`. If it was,\nwe cannot do a return statement in this function.\n\n## Types Revisited\n\nI introduced `type_compatible()` in the last part of the journey and said\nthat I wanted to refactor it. Now that I've added the `long` type, it's\nbecome necessary to do this. So here is the new version in `types.c`.\nYou may want to revisit the commentary on it from the last part of the journey.\n\n```c\n// Given two primitive types,\n// return true if they are compatible,\n// false otherwise. Also return either\n// zero or an A_WIDEN operation if one\n// has to be widened to match the other.\n// If onlyright is true, only widen left to right.\nint type_compatible(int *left, int *right, int onlyright) {\n  int leftsize, rightsize;\n\n  // Same types, they are compatible\n  if (*left == *right) { *left = *right = 0; return (1); }\n  // Get the sizes for each type\n  leftsize = genprimsize(*left);\n  rightsize = genprimsize(*right);\n\n  // Types with zero size are not\n  // not compatible with anything\n  if ((leftsize == 0) || (rightsize == 0)) return (0);\n\n  // Widen types as required\n  if (leftsize < rightsize) { *left = A_WIDEN; *right = 0; return (1);\n  }\n  if (rightsize < leftsize) {\n    if (onlyright) return (0);\n    *left = 0; *right = A_WIDEN; return (1);\n  }\n  // Anything remaining is the same size\n  // and thus compatible\n  *left = *right = 0;\n  return (1);\n}\n```\n\nI now call `genprimsize()` in the generic code generator which calls\n`cgprimsize()` in `cg.c` to get the size of the various types:\n\n```c\n// Array of type sizes in P_XXX order.\n// 0 means no size. P_NONE, P_VOID, P_CHAR, P_INT, P_LONG\nstatic int psize[] = { 0,       0,      1,     4,     8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONG)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n```\n\nThis makes the type sizes platform dependent; other platforms can choose\ndifferent type sizes. It probably means my code to mark a P_INTLIT as a\n`char` not an `int` will need to be refactored:\n\n```c\n  if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n```\n\n## Ensuring Non-Void Functions Return a Value\n\nWe've just ensured that void functions can't return a value. Now how to\nwe ensure that non-void functions will always return a value? To do\nthis, we have to ensure that the last statement in the function is a\nreturn statement.\n\nDown at the bottom of `function_declaration()` in `decl.c`, I now have:\n\n```c\n  struct ASTnode *tree, *finalstmt;\n  ...\n  // If the function type isn't P_VOID, check that\n  // the last AST operation in the compound statement\n  // was a return statement\n  if (type != P_VOID) {\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n```\n\nThe wrinkle is that, if the function has exactly one statement, there is\nno A_GLUE AST node and there is only a left child in the tree which is\nthe compound statement.\n\nAt this point, we can:\n\n  + declare a function, store its type, and record we are in that function\n  + make a function call (either as an expression or a statement) with a\n    single argument\n  + return from a non-void function (only), and force that the last statement\n    in a non-void function is a return statement\n  + check and widen the expression being returned so as to match the\n    function's type definition\n\nOur AST tree now has A_RETURN and A_FUNCCAL nodes to with the return statements\nand function calls. Let's now see how they generate the assembly output.\n\n## Why a Single Argument?\n\nYou might, at this point, be asking: why do you want to have a single\nfunction argument, especially as that argument isn't available to the\nfunction?\n\nThe answer is that I want to replace the `print x;` statement in our\nlanguage with a real function call: `printint(x);`. To do this, we can\ncompile a real C function `printint()` and link it with the output from\nour compiler.\n\n## The New AST Nodes\n\nThere is not much new code in `genAST()` in `gen.c`:\n\n```c\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_FUNCCALL:\n      return (cgcall(leftreg, n->v.id));\n```\n\nA_RETURN doesn't return a value as it's not an expression. A_FUNCCALL\nis an expression of course.\n\n## Changes in the x86-64 Output\n\nAll the new code generation work is in the platform-specific code\ngenerator, `cg.c`. Let's have a look at this.\n\n### New Types\n\nFirstly, we now have `char`, `int` and `long`, and the x86-64 requires\nus to use the right register names for each type:\n\n```c\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\nstatic char *dreglist[4] = { \"%r8d\", \"%r9d\", \"%r10d\", \"%r11d\" }\n```\n\n### Defining, Loading and Storing Variables\n\nVariables now have three possible type. The code we generate needs to\nreflect this. Here are the changed functions:\n\n```c\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.comm\\t%s,%d,%d\\n\", Gsym[id].name, typesize, typesize);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbq\\t%s(\\%%rip), %s\\n\", Gsym[id].name,\n              reglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovzbl\\t%s(\\%%rip), %s\\n\", Gsym[id].name,\n              reglist[r]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(\\%%rip)\\n\", breglist[r],\n              Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(\\%%rip)\\n\", dreglist[r],\n              Gsym[id].name);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n```\n\n### Function Calls\n\nTo call a function with one argument, we need to copy the register\nwith the argument value into `%rdi`. On return, we need to copy\nthe returned value from `%rax` into the register that will have this\nnew value:\n\n```c\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n```\n\n### Function Returns\n\nTo return from a function from any point in the function's execution, we\nneed to jump to a label right at the bottom of the function. I've added\ncode in `function_declaration()` to make a label and store it in the\nsymbol table. As the return value leaves in the `%rax` register, we\nneed to copy into this register before we jump to the end label:\n\n```c\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n```\n\n### Changes to the Function Preamble and Postamble\n\nThere are no changes to the preamble, but previously we were setting\n`%rax` to zero on the return. We have to remove this bit of code:\n\n```c\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpopq %rbp\\n\" \"\\tret\\n\", Outfile);\n}\n```\n\n### Changes to the Initial Preamble\n\nUp to now, I've been manually inserting an assembly version of\n`printint()` at the beginning of our assembly output. We no longer\nneed this, as we can compile a real C function `printint()` and link it with\nthe output from our compiler.\n\n## Testing the Changes\n\nThere is a new test program, `tests/input14`:\n\n```c\nint fred() {\n  return(20);\n}\n\nvoid main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n```\n\nWe firstly print 10, then call `fred()` which returns 20 and print this out.\nFinally, we call `fred()` again, add its return value to 10 and print out 30.\nThis demonstrates function calls with a single value, and function returns.\nHere is the test results:\n\n```\ncc -o comp1 -g cg.c decl.c expr.c gen.c main.c misc.c scan.c\n    stmt.c sym.c tree.c types.c\n./comp1 tests/input14\ncc -o out out.s lib/printint.c\n./out; true\n10\n20\n30\n```\n\nNote that we link our assembly output with `lib/printint.c`:\n\n```c\n#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n```\n\n## So Nearly C Now\n\nWith this change, we can do this:\n\n```\n$ cat lib/printint.c tests/input14 > input14.c\n$ cc -o out input14.c\n$ ./out \n10\n20\n30\n```\n\nIn other words, our language is enough of a subset of C that we can\ncompile it with other C functions to get an executable. Excellent!\n\n## Conclusion and What's Next\n\nWe've just added a simple version of function calls, function returns\nplus a new data type. As I expected, it wasn't trivial but I think the\nchanges are mostly sensible.\n\nIn the next part of our compiler writing journey, we will port our\ncompiler to a new hardware platform, the ARM CPU on a Raspberry Pi. [Next step](../14_ARM_Platform/Readme.md)\n"
  },
  {
    "path": "13_Functions_pt2/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\nstatic char *dreglist[4] = { \"%r8d\", \"%r9d\", \"%r10d\", \"%r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbq\\t%s(\\%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovzbl\\t%s(\\%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(\\%%rip)\\n\", breglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(\\%%rip)\\n\", dreglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONG)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.comm\\t%s,%d,%d\\n\", Gsym[id].name, typesize, typesize);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n"
  },
  {
    "path": "13_Functions_pt2/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\nstatic char *dreglist[4] = { \"r8d\", \"r9d\", \"r10d\", \"r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\tsection\\t.text\\n\"\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r], reglist[r]);\n      fprintf(Outfile, \"\\tmov\\t%s, dword [%s]\\n\", dreglist[r], \n              Gsym[id].name);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONG)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\tcommon\\t%s %d:%d\\n\", Gsym[id].name, typesize, typesize);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n"
  },
  {
    "path": "13_Functions_pt2/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n"
  },
  {
    "path": "13_Functions_pt2/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and\n// return a primitive type enum value\nint parse_type(int t) {\n  if (t == T_CHAR)\n    return (P_CHAR);\n  if (t == T_INT)\n    return (P_INT);\n  if (t == T_LONG)\n    return (P_LONG);\n  if (t == T_VOID)\n    return (P_VOID);\n  fatald(\"Illegal type, token\", t);\n}\n\n// variable_declaration: type identifier ';'  ;\n//\n// Parse the declaration of a variable\nvoid var_declaration(void) {\n  int id, type;\n\n  // Get the type of the variable, then the identifier\n  type = parse_type(Token.token);\n  scan(&Token);\n  ident();\n  // Text now has the identifier's name.\n  // Add it as a known identifier\n  // and generate its space in assembly\n  id = addglob(Text, type, S_VARIABLE, 0);\n  genglobsym(id);\n  // Get the trailing semicolon\n  semi();\n}\n\n//\n// function_declaration: type identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function\nstruct ASTnode *function_declaration(void) {\n  struct ASTnode *tree, *finalstmt;\n  int nameslot, type, endlabel;\n\n  // Get the type of the variable, then the identifier\n  type = parse_type(Token.token);\n  scan(&Token);\n  ident();\n\n  // Get a label-id for the end label, add the function\n  // to the symbol table, and set the Functionid global\n  // to the function's symbol-id\n  endlabel = genlabel();\n  nameslot = addglob(Text, type, S_FUNCTION, endlabel);\n  Functionid = nameslot;\n\n  // Scan in the parentheses\n  lparen();\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID, check that\n  // the last AST operation in the compound statement\n  // was a return statement\n  if (type != P_VOID) {\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, nameslot));\n}\n"
  },
  {
    "path": "13_Functions_pt2/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\nvoid genglobsym(int id);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nvoid cgprintint(int r);\nint cgcall(int r, int id);\nint cgstorglob(int r, int id);\nvoid cgglobsym(int id);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\n\n// expr.c\nstruct ASTnode *funccall(void);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name, int type, int stype, int endlabel);\n\n// decl.c\nvoid var_declaration(void);\nstruct ASTnode *function_declaration(void);\n\n// types.c\nint type_compatible(int *left, int *right, int onlyright);\n"
  },
  {
    "path": "13_Functions_pt2/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  // Operators\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n  // Structural tokens\n  T_INTLIT, T_SEMI, T_ASSIGN, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  // Other keywords\n  T_PRINT, T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ADD = 1, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT,\n  A_IDENT, A_LVIDENT, A_ASSIGN, A_PRINT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n};\n"
  },
  {
    "path": "13_Functions_pt2/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a function call with a single expression\n// argument and return its AST\nstruct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined,\n  // then make a leaf node for it. XXX Add structural type test\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Gsym[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n\tn = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n      break;\n\n    case T_IDENT:\n      // This could be a variable or a function call.\n      // Scan in the next token to find out\n      scan(&Token);\n\n      // It's a '(', so a function call\n      if (Token.token == T_LPAREN)\n\treturn (funccall());\n\n      // Not a function call, so reject the new token\n      reject_token(&Token);\n\n      // Check that the variable exists. XXX Add structural type test\n      id = findglob(Text);\n      if (id == -1)\n\tfatals(\"Unknown variable\", Text);\n\n      // Make a leaf AST node for it\n      n = mkastleaf(A_IDENT, Gsym[id].type, id);\n      break;\n\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into an AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int arithop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_PLUS, T_MINUS\n  20, 20,\t\t\t// T_STAR, T_SLASH\n  30, 30,\t\t\t// T_EQ, T_NE\n  40, 40, 40, 40\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int lefttype, righttype;\n  int tokentype;\n\n  // Get the primary tree on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Ensure the two types are compatible.\n    lefttype = left->type;\n    righttype = right->type;\n    if (!type_compatible(&lefttype, &righttype, 0))\n      fatal(\"Incompatible types\");\n\n    // Widen either side if required. type vars are A_WIDEN now\n    if (lefttype)\n      left = mkastunary(lefttype, right->type, left, 0);\n    if (righttype)\n      right = mkastunary(righttype, left->type, right, 0);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon or ')', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "13_Functions_pt2/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOREG, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOREG, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\n// and an optional ELSE clause\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOREG, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, the register (if any) that holds\n// the previous rvalue, and the AST op of the parent,\n// generate assembly code recursively.\n// Return the register id with the tree's final value\nint genAST(struct ASTnode *n, int reg, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We now have specific AST node handling at the top\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOREG, n->op);\n      genfreeregs();\n      genAST(n->right, NOREG, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      cgfuncpreamble(n->v.id);\n      genAST(n->left, NOREG, n->op);\n      cgfuncpostamble(n->v.id);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOREG, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, leftreg, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, reg));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue, n->type));\n    case A_IDENT:\n      return (cgloadglob(n->v.id));\n    case A_LVIDENT:\n      return (cgstorglob(reg, n->v.id));\n    case A_ASSIGN:\n      // The work has already been done, return the result\n      return (rightreg);\n    case A_PRINT:\n      // Print the left-child's value\n      // and return no register\n      genprintint(leftreg);\n      genfreeregs();\n      return (NOREG);\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_FUNCCALL:\n      return (cgcall(leftreg, n->v.id));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "13_Functions_pt2/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n"
  },
  {
    "path": "13_Functions_pt2/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nvoid main(int argc, char *argv[]) {\n  struct ASTnode *tree;\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n\n  // For now, ensure that void printint() is defined\n  addglob(\"printint\", P_CHAR, S_FUNCTION, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  while (1) {\t\t\t// Parse a function and\n    tree = function_declaration();\n    genAST(tree, NOREG, 0);\t// generate the assembly code for it\n    if (Token.token == T_EOF)\t// Stop when we have reached EOF\n      break;\n  }\n  fclose(Outfile);\t\t// Close the output file and exit\n  exit(0);\n}\n"
  },
  {
    "path": "13_Functions_pt2/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "13_Functions_pt2/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'p':\n      if (!strcmp(s, \"print\"))\n\treturn (T_PRINT);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tfatalc(\"Unrecognised character\", c);\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif (tokentype = keyword(Text)) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "13_Functions_pt2/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: print_statement\n//      |     declaration\n//      |     assignment_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n// print_statement: 'print' expression ';'  ;\n//\nstatic struct ASTnode *print_statement(void) {\n  struct ASTnode *tree;\n  int lefttype, righttype;\n  int reg;\n\n  // Match a 'print' as the first token\n  match(T_PRINT, \"print\");\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure the two types are compatible.\n  lefttype = P_INT;\n  righttype = tree->type;\n  if (!type_compatible(&lefttype, &righttype, 0))\n    fatal(\"Incompatible types\");\n\n  // Widen the tree if required. \n  if (righttype)\n    tree = mkastunary(righttype, P_INT, tree, 0);\n\n  // Make an print AST tree\n  tree = mkastunary(A_PRINT, P_NONE, tree, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// assignment_statement: identifier '=' expression ';'   ;\n//\n// Parse an assignment statement and return its AST\nstatic struct ASTnode *assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int lefttype, righttype;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // This could be a variable or a function call.\n  // If next token is '(', it's a function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // Not a function call, on with an assignment then!\n  // Check the identifier has been defined then make a leaf node for it\n  // XXX Add structural type test\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared variable\", Text);\n  }\n  right = mkastleaf(A_LVIDENT, Gsym[id].type, id);\n\n  // Ensure we have an equals sign\n  match(T_ASSIGN, \"=\");\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Ensure the two types are compatible.\n  lefttype = left->type;\n  righttype = right->type;\n  if (!type_compatible(&lefttype, &righttype, 1))\n    fatal(\"Incompatible types\");\n\n  // Widen the left if required.\n  if (lefttype)\n    left = mkastunary(lefttype, right->type, left, 0);\n\n  // Make an assignment AST tree\n  tree = mkastnode(A_ASSIGN, P_INT, left, NULL, right, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n  int returntype, functype;\n\n  // Can't return a value if function returns P_VOID\n  if (Gsym[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  returntype = tree->type;\n  functype = Gsym[Functionid].type;\n  if (!type_compatible(&returntype, &functype, 1))\n    fatal(\"Incompatible types\");\n\n  // Widen the left if required.\n  if (returntype)\n    tree = mkastunary(returntype, functype, tree, 0);\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement\n// and return its AST\nstatic struct ASTnode *single_statement(void) {\n  switch (Token.token) {\n    case T_PRINT:\n      return (print_statement());\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n      var_declaration();\n      return (NULL);\t\t// No AST generated here\n    case T_IDENT:\n      return (assignment_statement());\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_PRINT || tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "13_Functions_pt2/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic int Globs = 0;\t\t// Position of next free global symbol slot\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table.\n// Also set up its type and structural type.\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int endlabel) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  Gsym[y].type = type;\n  Gsym[y].stype = stype;\n  Gsym[y].endlabel = endlabel;\n  return (y);\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input01",
    "content": "void main()\n{ print 12 * 3;\n  print 18 - 2 * 4;\n  print 1 + 2 + 9 - 5/2 + 3*5;\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input02",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  print fred + jim;\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input03",
    "content": "void main()\n{\n  int x;\n  x= 1;     print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input04",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  print x;\n  x= 7 <= 9; print x;\n  x= 7 != 9; print x;\n  x= 7 == 7; print x;\n  x= 7 >= 7; print x;\n  x= 7 <= 7; print x;\n  x= 9 > 7;  print x;\n  x= 9 >= 7; print x;\n  x= 9 != 7; print x;\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input05",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    print i;\n  } else {\n    print j;\n  }\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input06",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    print i;\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input07",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input08",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input09",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { print 2 * b - a; }\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input10",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; print j;\n  i= 10; print i;\n\n  for (i= 1;   i <= 5; i= i + 1) { print i; }\n  for (j= 253; j != 2; j= j + 1) { print j; }\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input11",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; print i;\n  j= 20; print j;\n  k= 30; print k;\n\n  for (i= 1;   i <= 5; i= i + 1) { print i; }\n  for (j= 253; j != 4; j= j + 1) { print j; }\n  for (k= 1;   k <= 5; k= k + 1) { print k; }\n  return(i);\n  print 12345;\n  return(3);\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input12",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  print x;\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input13",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/input14",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "13_Functions_pt2/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > out.$i\n     rm -f out out.s\n   fi\ndone\n"
  },
  {
    "path": "13_Functions_pt2/tests/mktestsn",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -o out out.o ../lib/printint.c\n     ./out > out.$i\n     rm -f out out.s\n   fi\ndone\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input01",
    "content": "36\n10\n25\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input02",
    "content": "17\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input03",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input04",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input05",
    "content": "6\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input06",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input07",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input08",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input09",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input10",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input11",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input12",
    "content": "5\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input13",
    "content": "23\n56\n"
  },
  {
    "path": "13_Functions_pt2/tests/out.input14",
    "content": "10\n20\n30\n"
  },
  {
    "path": "13_Functions_pt2/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "13_Functions_pt2/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -o out out.o ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "13_Functions_pt2/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n"
  },
  {
    "path": "13_Functions_pt2/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given two primitive types,\n// return true if they are compatible,\n// false otherwise. Also return either\n// zero or an A_WIDEN operation if one\n// has to be widened to match the other.\n// If onlyright is true, only widen left to right.\nint type_compatible(int *left, int *right, int onlyright) {\n  int leftsize, rightsize;\n\n  // Same types, they are compatible\n  if (*left == *right) {\n    *left = *right = 0;\n    return (1);\n  }\n  // Get the sizes for each type\n  leftsize = genprimsize(*left);\n  rightsize = genprimsize(*right);\n\n  // Types with zero size are not\n  // not compatible with anything\n  if ((leftsize == 0) || (rightsize == 0))\n    return (0);\n\n  // Widen types as required\n  if (leftsize < rightsize) {\n    *left = A_WIDEN;\n    *right = 0;\n    return (1);\n  }\n  if (rightsize < leftsize) {\n    if (onlyright)\n      return (0);\n    *left = 0;\n    *right = A_WIDEN;\n    return (1);\n  }\n  // Anything remaining is the same size\n  // and thus compatible\n  *left = *right = 0;\n  return (1);\n}\n"
  },
  {
    "path": "14_ARM_Platform/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g -Wall $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g $(SRCN)\n\ncomp1arm: $(ARMSRCS)\n\tcc -o comp1arm -g -Wall $(ARMSRCS)\n\tcp comp1arm comp1\n\nclean:\n\trm -f comp1 comp1arm compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: comp1arm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\ntest14: comp1 tests/input14 lib/printint.c\n\t./comp1 tests/input14\n\tcc -o out out.s lib/printint.c\n\t./out\n\narmtest14: comp1arm tests/input14 lib/printint.c\n\t./comp1 tests/input14\n\tcc -o out out.s lib/printint.c\n\t./out\n\ntest14n: compn tests/input14 lib/printint.c\n\t./compn tests/input14\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out lib/printint.c out.o\n\t./out\n"
  },
  {
    "path": "14_ARM_Platform/Readme.md",
    "content": "# Part 14: Generating ARM Assembly Code\n\nIn this part of our compiler writing journey, I've ported the compiler\nover to the ARM CPU on the\n[Raspberry Pi 4](https://en.wikipedia.org/wiki/Raspberry_Pi).\n\nI should preface this section by saying that, while I know MIPS assembly\nlanguage quite well, I only knew a bit of x86-32 assembly language when I\nstarted this journey, and nothing about x86-64 nor ARM assembly language.\n\nWhat I've been doing along the way is compiling example C programs down\nto an assembler with various C compilers to see what sort of assembly\nlanguage they produce. That's what I've done here  to write the ARM\noutput for this compiler.\n\n## The Major Differences\n\nFirstly, ARM is a RISC CPU and x86-64 is a CISC CPU. There are fewer\naddressing modes on the ARM when compared to the x86-64. There are also\nother interesting constraints that occur when generating ARM assembly code.\nSo I will start with the major differences, and leave the main similarities\nto later.\n\n### ARM Registers\n\nARM has heaps more registers than x86-64. That said, I'm sticking with four\nregisters to allocate: `r4`,`r5`, `r6` and `r7`. We will see that `r0` and\n`r3` get used for other things below.\n\n### Addressing Global Variables\n\nOn x86-64, we only have to declare a global variable with a line like:\n\n```\n        .comm   i,4,4        # int variable\n        .comm   j,1,1        # char variable\n``` \n\nand, later, we can load and store to these variables easily:\n\n```\n        movb    %r8b, j(%rip)    # Store to j\n        movl    %r8d, i(%rip)    # Store to i\n        movzbl  i(%rip), %r8     # Load from i\n        movzbq  j(%rip), %r8     # Load from j\n```\n\nWith ARM, we have to manually allocate space for all global variables\nin our program postamble:\n\n```\n        .comm   i,4,4\n        .comm   j,1,1\n...\n.L2:\n        .word i\n        .word j\n```\n\nTo access these, we need to load a register with the address of each\nvariable, and load a second register from that address:\n\n```\n        ldr     r3, .L2+0\n        ldr     r4, [r3]        # Load i\n        ldr     r3, .L2+4\n        ldr     r4, [r3]        # Load j\n```\n\nStores to variables are similar:\n\n```\n        mov     r4, #20\n        ldr     r3, .L2+4\n        strb    r4, [r3]        # i= 20\n        mov     r4, #10\n        ldr     r3, .L2+0\n        str     r4, [r3]        # j= 10\n```\n\nThere is now this code in `cgpostamble()` to generate the table of .words:\n\n```c\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Gsym[i].name);\n  }\n```\n\nThis also means that we need to determine the offset from `.L2` for each\nglobal variable. Following the KISS principle, I manually calculate the\noffset each time I want to load `r3` with the address of a variable.\nYes, I should calculate each offset once and store it somewhere; later!\n\n```c\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n```\n\n### Loading Int Literals\n\nThe size of an integer literal in a load instruction is limited to 11 bits\nand I think this is a signed value. Thus, we can't put large integer literals\ninto a single instruction. That answer is to store the literal values in\nmemory, like variables. So I keep a list of previously-used literal\nvalues. In the postamble, I output them following the `.L3` label. And, like\nvariables, I walk this list to determine the offset of any literal from\nthe `.L3` label:\n\n```c\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n```\n\n### The Function Preamble\n\nI'm going to give you the function preamble, but I am not completely\nsure what each instruction does. Here it is for `int main(int x)`:\n\n```\n  .text\n  .globl        main\n  .type         main, %function\n  main:         push  {fp, lr}          # Save the frame and stack pointers\n                add   fp, sp, #4        # Add sp+4 to the stack pointer\n                sub   sp, sp, #8        # Lower the stack pointer by 8\n                str   r0, [fp, #-8]     # Save the argument as a local var?\n```\n\nand here's the function postamble to return a single value:\n\n```\n                sub   sp, fp, #4        # ???\n                pop   {fp, pc}          # Pop the frame and stack pointers\n```\n\n### Comparisons Returning 0 or 1\n\nWith the x86-64 there's an instruction to set a register to 0 or 1\nbased on the comparison being true, e.g. `sete`, but then we have to\nzero-fill the rest of the register with `movzbq`. With the ARM, we run\ntwo separate instructions which set a register to a value if the condition\nwe want is true or false, e.g.\n\n```\n                moveq r4, #1            # Set r4 to 1 if values were equal\n                movne r4, #0            # Set r4 to 0 if values were not equal\n```\n\n## A Comparison of Similar x86-64 and ARM Assembly Output\n\nI think that's all the major differences out of the road. So below\nis a comparison of the `cgXXX()` operation, any specific type for that\noperation, and an example x86-64 and ARM instruction sequence to\nperform it.\n\n| Operation(type) | x86-64 Version | ARM Version |\n|-----------------|----------------|-------------|\ncgloadint() | movq $12, %r8 | mov r4, #13 |\ncgloadglob(char) | movzbq foo(%rip), %r8 | ldr r3, .L2+#4 |\n| | | ldr r4, [r3] |\ncgloadglob(int) | movzbl foo(%rip), %r8 | ldr r3, .L2+#4 |\n| | | ldr r4, [r3] |\ncgloadglob(long) | movq foo(%rip), %r8 | ldr r3, .L2+#4 |\n| | | ldr r4, [r3] |\nint cgadd() | addq %r8, %r9 | add r4, r4, r5 |\nint cgsub() | subq %r8, %r9 | sub r4, r4, r5 |\nint cgmul() | imulq %r8, %r9 | mul r4, r4, r5 |\nint cgdiv() | movq %r8,%rax | mov r0, r4 |\n| | cqo | mov r1, r5 |\n| | idivq %r8 | bl __aeabi_idiv |\n| | movq %rax,%r8 | mov r4, r0 |\ncgprintint() | movq %r8, %rdi | mov r0, r4 |\n| | call printint | bl printint |\n| | | nop |\ncgcall() | movq %r8, %rdi | mov r0, r4 |\n| | call foo | bl foo |\n| | movq %rax, %r8 | mov r4, r0 |\ncgstorglob(char) | movb %r8, foo(%rip) | ldr r3, .L2+#4 |\n| | | strb r4, [r3] |\ncgstorglob(int) | movl %r8, foo(%rip) | ldr r3, .L2+#4 |\n| | | str r4, [r3] |\ncgstorglob(long) | movq %r8, foo(%rip) | ldr r3, .L2+#4 |\n| | | str r4, [r3] |\ncgcompare_and_set() | cmpq %r8, %r9 | cmp r4, r5 |\n| | sete %r8 | moveq r4, #1 |\n| | movzbq %r8, %r8 | movne r4, #1 |\ncgcompare_and_jump() | cmpq %r8, %r9 | cmp r4, r5 |\n| | je L2 | beq L2 |\ncgreturn(char) | movzbl %r8, %eax | mov r0, r4 |\n| | jmp L2 | b L2 |\ncgreturn(int) | movl %r8, %eax | mov r0, r4 |\n| | jmp L2 | b L2 |\ncgreturn(long) | movq %r8, %rax | mov r0, r4 |\n| | jmp L2 | b L2 |\n\n## Testing the ARM Code Generator\n\nIf you copy the compiler from this part of the journey to\na Raspberry Pi 3 or 4, you should be able to do:\n\n```\n$ make armtest\ncc -o comp1arm -g -Wall cg_arm.c decl.c expr.c gen.c main.c misc.c\n      scan.c stmt.c sym.c tree.c types.c\ncp comp1arm comp1\n(cd tests; chmod +x runtests; ./runtests)\ninput01: OK\ninput02: OK\ninput03: OK\ninput04: OK\ninput05: OK\ninput06: OK\ninput07: OK\ninput08: OK\ninput09: OK\ninput10: OK\ninput11: OK\ninput12: OK\ninput13: OK\ninput14: OK\n\n$ make armtest14\n./comp1 tests/input14\ncc -o out out.s lib/printint.c\n./out\n10\n20\n30\n```\n\n## Conclusion and What's Next\n\nIt did take me a bit of head scratching to get the ARM version of\nthe code generator `cg_arm.c` to correctly compile all of the test\ninputs. It was mostly straight-forward, I just wasn't familiar with\nthe architecture and instruction set.\n\nIt should be relatively easy to port the compiler to a platform with\n3 or 4 registers, 2 or so data sizes and a stack (and stack frames).\nAs we go forward, I'll try to keep both `cg.c` and `cg_arm.c`\nfunctionally in sync.\n\nIn the next part of our compiler writing journey, we will add the `char`\npointer to the language, as well as the '*' and '&' unary operators. [Next step](../15_Pointers_pt1/Readme.md)\n"
  },
  {
    "path": "14_ARM_Platform/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\nstatic char *dreglist[4] = { \"%r8d\", \"%r9d\", \"%r10d\", \"%r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return(NOREG);\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbq\\t%s(\\%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovzbl\\t%s(\\%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(\\%%rip)\\n\", breglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(\\%%rip)\\n\", dreglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONG)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.comm\\t%s,%d,%d\\n\", Gsym[id].name, typesize, typesize);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n"
  },
  {
    "path": "14_ARM_Platform/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Gsym[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\tprintint\\n\");\n  fprintf(Outfile, \"\\tnop\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n    fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONG)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.comm\\t%s,%d,%d\\n\", Gsym[id].name, typesize, typesize);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Gsym[id].endlabel);\n}\n"
  },
  {
    "path": "14_ARM_Platform/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\nstatic char *dreglist[4] = { \"r8d\", \"r9d\", \"r10d\", \"r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return(NOREG);\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\tsection\\t.text\\n\"\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r], reglist[r]);\n      fprintf(Outfile, \"\\tmov\\t%s, dword [%s]\\n\", dreglist[r], \n              Gsym[id].name);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONG)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\tcommon\\t%s %d:%d\\n\", Gsym[id].name, typesize, typesize);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n"
  },
  {
    "path": "14_ARM_Platform/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n"
  },
  {
    "path": "14_ARM_Platform/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and\n// return a primitive type enum value\nint parse_type(int t) {\n  if (t == T_CHAR)\n    return (P_CHAR);\n  if (t == T_INT)\n    return (P_INT);\n  if (t == T_LONG)\n    return (P_LONG);\n  if (t == T_VOID)\n    return (P_VOID);\n  fatald(\"Illegal type, token\", t);\n  return(0);\t// Keep -Wall happy\n}\n\n// variable_declaration: type identifier ';'  ;\n//\n// Parse the declaration of a variable\nvoid var_declaration(void) {\n  int id, type;\n\n  // Get the type of the variable, then the identifier\n  type = parse_type(Token.token);\n  scan(&Token);\n  ident();\n  // Text now has the identifier's name.\n  // Add it as a known identifier\n  // and generate its space in assembly\n  id = addglob(Text, type, S_VARIABLE, 0);\n  genglobsym(id);\n  // Get the trailing semicolon\n  semi();\n}\n\n//\n// function_declaration: type identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function\nstruct ASTnode *function_declaration(void) {\n  struct ASTnode *tree, *finalstmt;\n  int nameslot, type, endlabel;\n\n  // Get the type of the variable, then the identifier\n  type = parse_type(Token.token);\n  scan(&Token);\n  ident();\n\n  // Get a label-id for the end label, add the function\n  // to the symbol table, and set the Functionid global\n  // to the function's symbol-id\n  endlabel = genlabel();\n  nameslot = addglob(Text, type, S_FUNCTION, endlabel);\n  Functionid = nameslot;\n\n  // Scan in the parentheses\n  lparen();\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID, check that\n  // the last AST operation in the compound statement\n  // was a return statement\n  if (type != P_VOID) {\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, nameslot));\n}\n"
  },
  {
    "path": "14_ARM_Platform/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\nvoid genglobsym(int id);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nvoid cgprintint(int r);\nint cgcall(int r, int id);\nint cgstorglob(int r, int id);\nvoid cgglobsym(int id);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\n\n// expr.c\nstruct ASTnode *funccall(void);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name, int type, int stype, int endlabel);\n\n// decl.c\nvoid var_declaration(void);\nstruct ASTnode *function_declaration(void);\n\n// types.c\nint type_compatible(int *left, int *right, int onlyright);\n"
  },
  {
    "path": "14_ARM_Platform/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  // Operators\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n  // Structural tokens\n  T_INTLIT, T_SEMI, T_ASSIGN, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  // Other keywords\n  T_PRINT, T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ADD = 1, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT,\n  A_IDENT, A_LVIDENT, A_ASSIGN, A_PRINT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n};\n"
  },
  {
    "path": "14_ARM_Platform/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a function call with a single expression\n// argument and return its AST\nstruct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined,\n  // then make a leaf node for it. XXX Add structural type test\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Gsym[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n\tn = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n      break;\n\n    case T_IDENT:\n      // This could be a variable or a function call.\n      // Scan in the next token to find out\n      scan(&Token);\n\n      // It's a '(', so a function call\n      if (Token.token == T_LPAREN)\n\treturn (funccall());\n\n      // Not a function call, so reject the new token\n      reject_token(&Token);\n\n      // Check that the variable exists. XXX Add structural type test\n      id = findglob(Text);\n      if (id == -1)\n\tfatals(\"Unknown variable\", Text);\n\n      // Make a leaf AST node for it\n      n = mkastleaf(A_IDENT, Gsym[id].type, id);\n      break;\n\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into an AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int arithop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return(0);\t// Keep -Wall happy\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_PLUS, T_MINUS\n  20, 20,\t\t\t// T_STAR, T_SLASH\n  30, 30,\t\t\t// T_EQ, T_NE\n  40, 40, 40, 40\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int lefttype, righttype;\n  int tokentype;\n\n  // Get the primary tree on the left.\n  // Fetch the next token at the same time.\n  left = primary();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Ensure the two types are compatible.\n    lefttype = left->type;\n    righttype = right->type;\n    if (!type_compatible(&lefttype, &righttype, 0))\n      fatal(\"Incompatible types\");\n\n    // Widen either side if required. type vars are A_WIDEN now\n    if (lefttype)\n      left = mkastunary(lefttype, right->type, left, 0);\n    if (righttype)\n      right = mkastunary(righttype, left->type, right, 0);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon or ')', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "14_ARM_Platform/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOREG, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOREG, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\n// and an optional ELSE clause\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOREG, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, the register (if any) that holds\n// the previous rvalue, and the AST op of the parent,\n// generate assembly code recursively.\n// Return the register id with the tree's final value\nint genAST(struct ASTnode *n, int reg, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We now have specific AST node handling at the top\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOREG, n->op);\n      genfreeregs();\n      genAST(n->right, NOREG, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      cgfuncpreamble(n->v.id);\n      genAST(n->left, NOREG, n->op);\n      cgfuncpostamble(n->v.id);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOREG, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, leftreg, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, reg));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue, n->type));\n    case A_IDENT:\n      return (cgloadglob(n->v.id));\n    case A_LVIDENT:\n      return (cgstorglob(reg, n->v.id));\n    case A_ASSIGN:\n      // The work has already been done, return the result\n      return (rightreg);\n    case A_PRINT:\n      // Print the left-child's value\n      // and return no register\n      genprintint(leftreg);\n      genfreeregs();\n      return (NOREG);\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_FUNCCALL:\n      return (cgcall(leftreg, n->v.id));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "14_ARM_Platform/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n"
  },
  {
    "path": "14_ARM_Platform/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n  Globs = 0;\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nint main(int argc, char *argv[]) {\n  struct ASTnode *tree;\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n\n  // For now, ensure that void printint() is defined\n  addglob(\"printint\", P_CHAR, S_FUNCTION, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  while (1) {\t\t\t// Parse a function and\n    tree = function_declaration();\n    genAST(tree, NOREG, 0);\t// generate the assembly code for it\n    if (Token.token == T_EOF)\t// Stop when we have reached EOF\n      break;\n  }\n  genpostamble();\n  fclose(Outfile);\t\t// Close the output file and exit\n  return(0);\n}\n"
  },
  {
    "path": "14_ARM_Platform/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "14_ARM_Platform/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'p':\n      if (!strcmp(s, \"print\"))\n\treturn (T_PRINT);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tfatalc(\"Unrecognised character\", c);\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "14_ARM_Platform/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: print_statement\n//      |     declaration\n//      |     assignment_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n// print_statement: 'print' expression ';'  ;\n//\nstatic struct ASTnode *print_statement(void) {\n  struct ASTnode *tree;\n  int lefttype, righttype;\n\n  // Match a 'print' as the first token\n  match(T_PRINT, \"print\");\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure the two types are compatible.\n  lefttype = P_INT;\n  righttype = tree->type;\n  if (!type_compatible(&lefttype, &righttype, 0))\n    fatal(\"Incompatible types\");\n\n  // Widen the tree if required. \n  if (righttype)\n    tree = mkastunary(righttype, P_INT, tree, 0);\n\n  // Make an print AST tree\n  tree = mkastunary(A_PRINT, P_NONE, tree, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// assignment_statement: identifier '=' expression ';'   ;\n//\n// Parse an assignment statement and return its AST\nstatic struct ASTnode *assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int lefttype, righttype;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // This could be a variable or a function call.\n  // If next token is '(', it's a function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // Not a function call, on with an assignment then!\n  // Check the identifier has been defined then make a leaf node for it\n  // XXX Add structural type test\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared variable\", Text);\n  }\n  right = mkastleaf(A_LVIDENT, Gsym[id].type, id);\n\n  // Ensure we have an equals sign\n  match(T_ASSIGN, \"=\");\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Ensure the two types are compatible.\n  lefttype = left->type;\n  righttype = right->type;\n  if (!type_compatible(&lefttype, &righttype, 1))\n    fatal(\"Incompatible types\");\n\n  // Widen the left if required.\n  if (lefttype)\n    left = mkastunary(lefttype, right->type, left, 0);\n\n  // Make an assignment AST tree\n  tree = mkastnode(A_ASSIGN, P_INT, left, NULL, right, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n  int returntype, functype;\n\n  // Can't return a value if function returns P_VOID\n  if (Gsym[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  returntype = tree->type;\n  functype = Gsym[Functionid].type;\n  if (!type_compatible(&returntype, &functype, 1))\n    fatal(\"Incompatible types\");\n\n  // Widen the left if required.\n  if (returntype)\n    tree = mkastunary(returntype, functype, tree, 0);\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement\n// and return its AST\nstatic struct ASTnode *single_statement(void) {\n  switch (Token.token) {\n    case T_PRINT:\n      return (print_statement());\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n      var_declaration();\n      return (NULL);\t\t// No AST generated here\n    case T_IDENT:\n      return (assignment_statement());\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n  return(NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_PRINT || tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "14_ARM_Platform/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table.\n// Also set up its type and structural type.\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int endlabel) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  Gsym[y].type = type;\n  Gsym[y].stype = stype;\n  Gsym[y].endlabel = endlabel;\n  return (y);\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input01",
    "content": "void main()\n{ print 12 * 3;\n  print 18 - 2 * 4;\n  print 1 + 2 + 9 - 5/2 + 3*5;\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input02",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  print fred + jim;\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input03",
    "content": "void main()\n{\n  int x;\n  x= 1;     print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n  x= x + 1; print x;\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input04",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  print x;\n  x= 7 <= 9; print x;\n  x= 7 != 9; print x;\n  x= 7 == 7; print x;\n  x= 7 >= 7; print x;\n  x= 7 <= 7; print x;\n  x= 9 > 7;  print x;\n  x= 9 >= 7; print x;\n  x= 9 != 7; print x;\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input05",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    print i;\n  } else {\n    print j;\n  }\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input06",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    print i;\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input07",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input08",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input09",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    print i;\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { print 2 * b - a; }\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input10",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; print j;\n  i= 10; print i;\n\n  for (i= 1;   i <= 5; i= i + 1) { print i; }\n  for (j= 253; j != 2; j= j + 1) { print j; }\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input11",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; print i;\n  j= 20; print j;\n  k= 30; print k;\n\n  for (i= 1;   i <= 5; i= i + 1) { print i; }\n  for (j= 253; j != 4; j= j + 1) { print j; }\n  for (k= 1;   k <= 5; k= k + 1) { print k; }\n  return(i);\n  print 12345;\n  return(3);\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input12",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  print x;\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input13",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/input14",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "14_ARM_Platform/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > out.$i\n     rm -f out out.s\n   fi\ndone\n"
  },
  {
    "path": "14_ARM_Platform/tests/mktestsn",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -o out out.o ../lib/printint.c\n     ./out > out.$i\n     rm -f out out.s\n   fi\ndone\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input01",
    "content": "36\n10\n25\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input02",
    "content": "17\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input03",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input04",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input05",
    "content": "6\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input06",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input07",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input08",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input09",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input10",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input11",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input12",
    "content": "5\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input13",
    "content": "23\n56\n"
  },
  {
    "path": "14_ARM_Platform/tests/out.input14",
    "content": "10\n20\n30\n"
  },
  {
    "path": "14_ARM_Platform/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "14_ARM_Platform/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -o out out.o ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "14_ARM_Platform/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n"
  },
  {
    "path": "14_ARM_Platform/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given two primitive types,\n// return true if they are compatible,\n// false otherwise. Also return either\n// zero or an A_WIDEN operation if one\n// has to be widened to match the other.\n// If onlyright is true, only widen left to right.\nint type_compatible(int *left, int *right, int onlyright) {\n  int leftsize, rightsize;\n\n  // Same types, they are compatible\n  if (*left == *right) {\n    *left = *right = 0;\n    return (1);\n  }\n  // Get the sizes for each type\n  leftsize = genprimsize(*left);\n  rightsize = genprimsize(*right);\n\n  // Types with zero size are not\n  // not compatible with anything\n  if ((leftsize == 0) || (rightsize == 0))\n    return (0);\n\n  // Widen types as required\n  if (leftsize < rightsize) {\n    *left = A_WIDEN;\n    *right = 0;\n    return (1);\n  }\n  if (rightsize < leftsize) {\n    if (onlyright)\n      return (0);\n    *left = 0;\n    *right = A_WIDEN;\n    return (1);\n  }\n  // Anything remaining is the same size\n  // and thus compatible\n  *left = *right = 0;\n  return (1);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g -Wall $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g -Wall $(SRCN)\n\ncomp1arm: $(ARMSRCS)\n\tcc -o comp1arm -g -Wall $(ARMSRCS)\n\tcp comp1arm comp1\n\nclean:\n\trm -f comp1 comp1arm compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: comp1arm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\ntest15: comp1 tests/input15.c lib/printint.c\n\t./comp1 tests/input15.c\n\tcc -o out out.s lib/printint.c\n\t./out\n\narmtest15: comp1arm tests/input15.c lib/printint.c\n\t./comp1 tests/input15.c\n\tcc -o out out.s lib/printint.c\n\t./out\n\ntest15n: compn tests/input15.c lib/printint.c\n\t./compn tests/input15.c\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out lib/printint.c out.o\n\t./out\n"
  },
  {
    "path": "15_Pointers_pt1/Readme.md",
    "content": "# Part 15: Pointers, part 1\n\nIn this part of our compiler writing journey, I want\nto begin the work to add pointers to our language.\nIn particular, I want to add this:\n\n + Declaration of pointer variables\n + Assignment of an address to a pointer\n + Dereferencing a pointer to get the value it points at\n\nGiven that this is a work in progress, I'm sure I will\nimplement a simplistic version that works for now, but\nlater on I will have to change or extend it for  to be\nmore general.\n\n## New Keywords and Tokens\n\nThere are no new keywords this time, only two new tokens:\n\n + '&', T_AMPER, and\n + '&&', T_LOGAND\n\nWe don't need T_LOGAND yet, but I might as well add this\ncode to `scan()` now:\n\n```c\n    case '&':\n      if ((c = next()) == '&') {\n        t->token = T_LOGAND;\n      } else {\n        putback(c);\n        t->token = T_AMPER;\n      }\n      break;\n```\n\n## New Code for Types\n\nI've added some new primitive types to the language\n(in `defs.h`):\n\n```c\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n```\n\nWe will have new unary prefix operators:\n\n + '&' to get the address of an identifier, and\n + '*' to dereference a pointer and get the value\n   it points at.\n\nThe type of expression that each operator produces\nis different to the type that each works on. We need\na couple of functions in `types.c` to make the type\nchange:\n\n```c\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOID: newtype = P_VOIDPTR; break;\n    case P_CHAR: newtype = P_CHARPTR; break;\n    case P_INT:  newtype = P_INTPTR;  break;\n    case P_LONG: newtype = P_LONGPTR; break;\n    default:\n      fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOIDPTR: newtype = P_VOID; break;\n    case P_CHARPTR: newtype = P_CHAR; break;\n    case P_INTPTR:  newtype = P_INT;  break;\n    case P_LONGPTR: newtype = P_LONG; break;\n    default:\n      fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n```\n\nNow, where are we going to use these functions?\n\n## Declaring Pointer Variables\n\nWe want to be able to declare scalar variables\nand pointer variables, e.g.\n\n```c\n  char  a; char *b;\n  int   d; int  *e;\n```\n\nWe already have a function `parse_type()` in `decl.c`\nthat converts the type keyword to a type. Let's extend\nit to scan the following token and change the type if\nthe next token is a '*':\n\n```c\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n    case T_VOID: type = P_VOID; break;\n    case T_CHAR: type = P_CHAR; break;\n    case T_INT:  type = P_INT;  break;\n    case T_LONG: type = P_LONG; break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR) break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n```\n\nThis will allow the programmer to try to do:\n\n```c\n   char *****fred;\n```\nThis will fail because `pointer_to()` can't convert\na P_CHARPTR to a P_CHARPTRPTR (yet). But the code\nin `parse_type()` is ready to do it!\n\n\nThe code in `var_declaration()` now quite\nhappily parses pointer variable declarations:\n\n```c\n// Parse the declaration of a variable\nvoid var_declaration(void) {\n  int id, type;\n\n  // Get the type of the variable\n  // which also scans in the identifier\n  type = parse_type();\n  ident();\n  ...\n}\n```\n\n### Prefix Operators '*' and '&'\n\nWith declarations out of the road, let's now look\nat parsing expressions where '*' and '&' are\noperators that come before an expression. The BNF\ngrammar looks like this:\n\n```\n prefix_expression: primary\n     | '*' prefix_expression\n     | '&' prefix_expression\n     ;\n```\n\nTechnically this allows:\n\n```\n   x= ***y;\n   a= &&&b;\n```\n\nTo prevent impossible uses of the two operators,\nwe add in some semantic checking. Here's the code:\n\n```c\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n    case T_AMPER:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Ensure that it's an identifier\n      if (tree->op != A_IDENT)\n        fatal(\"& operator must be followed by an identifier\");\n\n      // Now change the operator to A_ADDR and the type to\n      // a pointer to the original type\n      tree->op = A_ADDR; tree->type = pointer_to(tree->type);\n      break;\n    case T_STAR:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token); tree = prefix();\n\n      // For now, ensure it's either another deref or an\n      // identifier\n      if (tree->op != A_IDENT && tree->op != A_DEREF)\n        fatal(\"* operator must be followed by an identifier or *\");\n\n      // Prepend an A_DEREF operation to the tree\n      tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n      break;\n    default:\n      tree = primary();\n  }\n  return (tree);\n}\n```\n\nWe're still doing recursive descent, but we also put error\nchecks in to prevent input mistakes. Right now, the limitations\nin `value_at()` will prevent more than one '*' operator in a row,\nbut later on when we change `value_at()`, we won't have to come\nback and change `prefix()`.\n\nNote that `prefix()` also calls `primary()` when it doesn't see\na '*' or '&' operator. That allows us to change our existing code\nin `binexpr()`:\n\n```c\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int lefttype, righttype;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  // Used to be a call to primary().\n  left = prefix();\n  ...\n}\n```\n\n## New AST Node Types\n\nUp in `prefix()` I introduced two new AST node types\n(declared in `defs.h`):\n\n\n + A_DEREF: Dereference the pointer in the child node\n + A_ADDR: Get the address of the identifier in this node\n\nNote that the A_ADDR node isn't a parent node. For the\nexpression `&fred`, the code in `prefix()` replaces\nthe A_IDENT in the \"fred\" node with the A_ADDR node type.\n\n## Generating the New Assembly Code\n\nIn our generic code generator, `gen.c`, there are only\na few new lines to `genAST()`:\n\n```c\n    case A_ADDR:\n      return (cgaddress(n->v.id));\n    case A_DEREF:\n      return (cgderef(leftreg, n->left->type));\n```\n\nThe A_ADDR node generates the code to load the\naddress of the `n->v.id` identifier into a register.\nThe A_DEREF node take the pointer address in `lefreg`,\nand its associated type, and returns a register with\nthe value at this address.\n\n### x86-64 Implementation\n\nI worked out the following assembly output by reviewing\nthe assembly code generated by other compilers. It\nmight not be correct!\n\n```c\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n```\n\nThe `leaq` instruction loads the address of the named identifier.\nIn the section function, the `(%r8)` syntax loads the value that\nregister `%r8` points to.\n\n## Testing the New Functinality\n\nHere's our new test file, `tests/input15.c` and the result when we\ncompile it:\n\n```c\nint main() {\n  char  a; char *b; char  c;\n  int   d; int  *e; int   f;\n\n  a= 18; printint(a);\n  b= &a; c= *b; printint(c);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n\n```\n\n```\n$ make test15\ncc -o comp1 -g -Wall cg.c decl.c expr.c gen.c main.c misc.c\n   scan.c stmt.c sym.c tree.c types.c\n./comp1 tests/input15.c\ncc -o out out.s lib/printint.c\n./out\n18\n18\n12\n12\n```\n\nI decided to change our test files to end with the `.c`\nsuffix, now that they are actually C programs. I also\nchanged the `tests/mktests` script to generate the\n*correct* results by using a \"real\" compiler to\ncompile our test files.\n\n## Conclusion and What's Next\n\nWell, we have the start of pointers implemented. They\nare not completely correct yet. For example, if I write\nthis code:\n\n```c\nint main() {\n  int x; int y;\n  int *iptr;\n  x= 10; y= 20;\n  iptr= &x + 1;\n  printint( *iptr);\n}\n```\n\nit should print 20 because `&x + 1` should address\none `int` past `x`, i.e. `y`. This is eight bytes\naway from `x`. However, our compiler simply adds\none to the address of `x`, which is incorrect. I'll\nhave to work out how to fix this.\n\nIn the next part of our compiler writing journey, we will\ntry to fix this problem. [Next step](../16_Global_Vars/Readme.md)\n"
  },
  {
    "path": "15_Pointers_pt1/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\nstatic char *dreglist[4] = { \"%r8d\", \"%r9d\", \"%r10d\", \"%r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovzbl\\t%s(\\%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(\\%%rip)\\n\", breglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(\\%%rip)\\n\", dreglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.comm\\t%s,%d,%d\\n\", Gsym[id].name, typesize, typesize);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Gsym[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\tprintint\\n\");\n  fprintf(Outfile, \"\\tnop\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4, 4, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.comm\\t%s,%d,%d\\n\", Gsym[id].name, typesize, typesize);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  }\n  return (r);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\nstatic char *dreglist[4] = { \"r8d\", \"r9d\", \"r10d\", \"r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\tsection\\t.text\\n\"\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r], reglist[r]);\n      fprintf(Outfile, \"\\tmov\\t%s, dword [%s]\\n\", dreglist[r], \n              Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\tcommon\\t%s %d:%d\\n\", Gsym[id].name, typesize, typesize);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Gsym[id].name);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, word [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n"
  },
  {
    "path": "15_Pointers_pt1/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      break;\n    case T_INT:\n      type = P_INT;\n      break;\n    case T_LONG:\n      type = P_LONG;\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'  ;\n//\n// Parse the declaration of a variable\nvoid var_declaration(void) {\n  int id, type;\n\n  // Get the type of the variable\n  // which also scans in the identifier\n  type = parse_type();\n  ident();\n  // Text now has the identifier's name.\n  // Add it as a known identifier\n  // and generate its space in assembly\n  id = addglob(Text, type, S_VARIABLE, 0);\n  genglobsym(id);\n  // Get the trailing semicolon\n  semi();\n}\n\n//\n// function_declaration: type identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function\nstruct ASTnode *function_declaration(void) {\n  struct ASTnode *tree, *finalstmt;\n  int nameslot, type, endlabel;\n\n  // Get the type of the variable\n  // which also scans in the identifier\n  type = parse_type();\n  ident();\n\n  // Get a label-id for the end label, add the function\n  // to the symbol table, and set the Functionid global\n  // to the function's symbol-id\n  endlabel = genlabel();\n  nameslot = addglob(Text, type, S_FUNCTION, endlabel);\n  Functionid = nameslot;\n\n  // Scan in the parentheses\n  lparen();\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, nameslot));\n}\n"
  },
  {
    "path": "15_Pointers_pt1/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\nvoid genglobsym(int id);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nvoid cgprintint(int r);\nint cgcall(int r, int id);\nint cgstorglob(int r, int id);\nvoid cgglobsym(int id);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\n\n// expr.c\nstruct ASTnode *funccall(void);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name, int type, int stype, int endlabel);\n\n// decl.c\nvoid var_declaration(void);\nstruct ASTnode *function_declaration(void);\n\n// types.c\nint type_compatible(int *left, int *right, int onlyright);\nint pointer_to(int type);\nint value_at(int type);\n"
  },
  {
    "path": "15_Pointers_pt1/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  // Operators\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n  // Structural tokens\n  T_INTLIT, T_SEMI, T_ASSIGN, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_AMPER, T_LOGAND,\n  // Other keywords\n  T_PRINT, T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ADD = 1, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT,\n  A_IDENT, A_LVIDENT, A_ASSIGN, A_PRINT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n};\n"
  },
  {
    "path": "15_Pointers_pt1/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a function call with a single expression\n// argument and return its AST\nstruct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined,\n  // then make a leaf node for it. XXX Add structural type test\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Gsym[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n\tn = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n      break;\n\n    case T_IDENT:\n      // This could be a variable or a function call.\n      // Scan in the next token to find out\n      scan(&Token);\n\n      // It's a '(', so a function call\n      if (Token.token == T_LPAREN)\n\treturn (funccall());\n\n      // Not a function call, so reject the new token\n      reject_token(&Token);\n\n      // Check that the variable exists. XXX Add structural type test\n      id = findglob(Text);\n      if (id == -1)\n\tfatals(\"Unknown variable\", Text);\n\n      // Make a leaf AST node for it\n      n = mkastleaf(A_IDENT, Gsym[id].type, id);\n      break;\n\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into an AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int arithop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_PLUS, T_MINUS\n  20, 20,\t\t\t// T_STAR, T_SLASH\n  30, 30,\t\t\t// T_EQ, T_NE\n  40, 40, 40, 40\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*' prefix_expression\n//     | '&' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n    case T_AMPER:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Ensure that it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"& operator must be followed by an identifier\");\n\n      // Now change the operator to A_ADDR and the type to\n      // a pointer to the original type\n      tree->op = A_ADDR;\n      tree->type = pointer_to(tree->type);\n      break;\n    case T_STAR:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's either another deref or an\n      // identifier\n      if (tree->op != A_IDENT && tree->op != A_DEREF)\n\tfatal(\"* operator must be followed by an identifier or *\");\n\n      // Prepend an A_DEREF operation to the tree\n      tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n      break;\n    default:\n      tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int lefttype, righttype;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Ensure the two types are compatible.\n    lefttype = left->type;\n    righttype = right->type;\n    if (!type_compatible(&lefttype, &righttype, 0))\n      fatal(\"Incompatible types\");\n\n    // Widen either side if required. type vars are A_WIDEN now\n    if (lefttype)\n      left = mkastunary(lefttype, right->type, left, 0);\n    if (righttype)\n      right = mkastunary(righttype, left->type, right, 0);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon or ')', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOREG, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOREG, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\n// and an optional ELSE clause\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOREG, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, the register (if any) that holds\n// the previous rvalue, and the AST op of the parent,\n// generate assembly code recursively.\n// Return the register id with the tree's final value\nint genAST(struct ASTnode *n, int reg, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We now have specific AST node handling at the top\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOREG, n->op);\n      genfreeregs();\n      genAST(n->right, NOREG, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      cgfuncpreamble(n->v.id);\n      genAST(n->left, NOREG, n->op);\n      cgfuncpostamble(n->v.id);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOREG, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, leftreg, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, reg));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue, n->type));\n    case A_IDENT:\n      return (cgloadglob(n->v.id));\n    case A_LVIDENT:\n      return (cgstorglob(reg, n->v.id));\n    case A_ASSIGN:\n      // The work has already been done, return the result\n      return (rightreg);\n    case A_PRINT:\n      // Print the left-child's value\n      // and return no register\n      genprintint(leftreg);\n      genfreeregs();\n      return (NOREG);\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_FUNCCALL:\n      return (cgcall(leftreg, n->v.id));\n    case A_ADDR:\n      return (cgaddress(n->v.id));\n    case A_DEREF:\n      return (cgderef(leftreg, n->left->type));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "15_Pointers_pt1/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n  Globs = 0;\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nint main(int argc, char *argv[]) {\n  struct ASTnode *tree;\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n  // For now, ensure that void printint() is defined\n  addglob(\"printint\", P_CHAR, S_FUNCTION, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  while (1) {\t\t\t// Parse a function and\n    tree = function_declaration();\n    genAST(tree, NOREG, 0);\t// generate the assembly code for it\n    if (Token.token == T_EOF)\t// Stop when we have reached EOF\n      break;\n  }\n  genpostamble();\n  fclose(Outfile);\t\t// Close the output file and exit\n  return (0);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'p':\n      if (!strcmp(s, \"print\"))\n\treturn (T_PRINT);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tfatalc(\"Unrecognised character\", c);\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: print_statement\n//      |     declaration\n//      |     assignment_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n// print_statement: 'print' expression ';'  ;\n//\nstatic struct ASTnode *print_statement(void) {\n  struct ASTnode *tree;\n  int lefttype, righttype;\n\n  // Match a 'print' as the first token\n  match(T_PRINT, \"print\");\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure the two types are compatible.\n  lefttype = P_INT;\n  righttype = tree->type;\n  if (!type_compatible(&lefttype, &righttype, 0))\n    fatal(\"Incompatible types\");\n\n  // Widen the tree if required. \n  if (righttype)\n    tree = mkastunary(righttype, P_INT, tree, 0);\n\n  // Make an print AST tree\n  tree = mkastunary(A_PRINT, P_NONE, tree, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// assignment_statement: identifier '=' expression ';'   ;\n//\n// Parse an assignment statement and return its AST\nstatic struct ASTnode *assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int lefttype, righttype;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // This could be a variable or a function call.\n  // If next token is '(', it's a function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // Not a function call, on with an assignment then!\n  // Check the identifier has been defined then make a leaf node for it\n  // XXX Add structural type test\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared variable\", Text);\n  }\n  right = mkastleaf(A_LVIDENT, Gsym[id].type, id);\n\n  // Ensure we have an equals sign\n  match(T_ASSIGN, \"=\");\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Ensure the two types are compatible.\n  lefttype = left->type;\n  righttype = right->type;\n  if (!type_compatible(&lefttype, &righttype, 1))\n    fatal(\"Incompatible types\");\n\n  // Widen the left if required.\n  if (lefttype)\n    left = mkastunary(lefttype, right->type, left, 0);\n\n  // Make an assignment AST tree\n  tree = mkastnode(A_ASSIGN, P_INT, left, NULL, right, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n  int returntype, functype;\n\n  // Can't return a value if function returns P_VOID\n  if (Gsym[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  returntype = tree->type;\n  functype = Gsym[Functionid].type;\n  if (!type_compatible(&returntype, &functype, 1))\n    fatal(\"Incompatible types\");\n\n  // Widen the left if required.\n  if (returntype)\n    tree = mkastunary(returntype, functype, tree, 0);\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement\n// and return its AST\nstatic struct ASTnode *single_statement(void) {\n  switch (Token.token) {\n    case T_PRINT:\n      return (print_statement());\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n      var_declaration();\n      return (NULL);\t\t// No AST generated here\n    case T_IDENT:\n      return (assignment_statement());\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_PRINT || tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "15_Pointers_pt1/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table.\n// Also set up its type and structural type.\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int endlabel) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  Gsym[y].type = type;\n  Gsym[y].stype = stype;\n  Gsym[y].endlabel = endlabel;\n  return (y);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input01.c",
    "content": "void main()\n{ printint(12 * 3);\n  printint(18 - 2 * 4);\n  printint(1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input02.c",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printint(fred + jim);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input03.c",
    "content": "void main()\n{\n  int x;\n  x= 1;     printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input04.c",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  printint(x);\n  x= 7 <= 9; printint(x);\n  x= 7 != 9; printint(x);\n  x= 7 == 7; printint(x);\n  x= 7 >= 7; printint(x);\n  x= 7 <= 7; printint(x);\n  x= 9 > 7;  printint(x);\n  x= 9 >= 7; printint(x);\n  x= 9 != 7; printint(x);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input05.c",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printint(i);\n  } else {\n    printint(j);\n  }\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input06.c",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printint(i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input07.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input08.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input09.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printint(2 * b - a); }\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input10.c",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; printint(j);\n  i= 10; printint(i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 2; j= j + 1) { printint(j); }\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input11.c",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; printint(i);\n  j= 20; printint(j);\n  k= 30; printint(k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 4; j= j + 1) { printint(j); }\n  for (k= 1;   k <= 5; k= k + 1) { printint(k); }\n  return(i);\n  printint(12345);\n  return(3);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input12.c",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printint(x);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input13.c",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input14.c",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/input15.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printint(a);\n  b= &a; c= *b; printint(c);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "15_Pointers_pt1/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" ]\n   then\n     cc -o out $i ../lib/printint.c\n     ./out > out.$i\n     rm -f out\n   fi\ndone\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "15_Pointers_pt1/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "15_Pointers_pt1/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "15_Pointers_pt1/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -Wall -o out out.o ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "15_Pointers_pt1/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n"
  },
  {
    "path": "15_Pointers_pt1/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given two primitive types,\n// return true if they are compatible,\n// false otherwise. Also return either\n// zero or an A_WIDEN operation if one\n// has to be widened to match the other.\n// If onlyright is true, only widen left to right.\nint type_compatible(int *left, int *right, int onlyright) {\n  int leftsize, rightsize;\n\n  // Same types, they are compatible\n  if (*left == *right) {\n    *left = *right = 0;\n    return (1);\n  }\n  // Get the sizes for each type\n  leftsize = genprimsize(*left);\n  rightsize = genprimsize(*right);\n\n  // Types with zero size are not\n  // not compatible with anything\n  if ((leftsize == 0) || (rightsize == 0))\n    return (0);\n\n  // Widen types as required\n  if (leftsize < rightsize) {\n    *left = A_WIDEN;\n    *right = 0;\n    return (1);\n  }\n  if (rightsize < leftsize) {\n    if (onlyright)\n      return (0);\n    *left = 0;\n    *right = A_WIDEN;\n    return (1);\n  }\n  // Anything remaining is the same size\n  // and thus compatible\n  *left = *right = 0;\n  return (1);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOID:\n      newtype = P_VOIDPTR;\n      break;\n    case P_CHAR:\n      newtype = P_CHARPTR;\n      break;\n    case P_INT:\n      newtype = P_INTPTR;\n      break;\n    case P_LONG:\n      newtype = P_LONGPTR;\n      break;\n    default:\n      fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOIDPTR:\n      newtype = P_VOID;\n      break;\n    case P_CHARPTR:\n      newtype = P_CHAR;\n      break;\n    case P_INTPTR:\n      newtype = P_INT;\n      break;\n    case P_LONGPTR:\n      newtype = P_LONG;\n      break;\n    default:\n      fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n"
  },
  {
    "path": "16_Global_Vars/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g -Wall $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g -Wall $(SRCN)\n\ncomp1arm: $(ARMSRCS)\n\tcc -o comp1arm -g -Wall $(ARMSRCS)\n\tcp comp1arm comp1\n\nclean:\n\trm -f comp1 comp1arm compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: comp1arm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\ntest16: comp1 tests/input16.c lib/printint.c\n\t./comp1 tests/input16.c\n\tcc -o out out.s lib/printint.c\n\t./out\n\narmtest16: comp1arm tests/input16.c lib/printint.c\n\t./comp1 tests/input16.c\n\tcc -o out out.s lib/printint.c\n\t./out\n\ntest16n: compn tests/input16.c lib/printint.c\n\t./compn tests/input16.c\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out lib/printint.c out.o\n\t./out\n"
  },
  {
    "path": "16_Global_Vars/Readme.md",
    "content": "# Part 16: Declaring Global Variables Properly\n\nI did promise to look at the issue of adding offsets to pointers, but\nI need to do some thinking about that first. So I've decided to move\nglobal variable declarations out of function declarations. Actually,\nI've also left the parsing of variable declarations inside functions, because\nlater on we will change them to be local variable declarations.\n\nI also want to extend our grammar so that we can declare multiple\nvariables with the same type at the same time, e.g.\n\n```c\n  int x, y, z;\n```\n\n## The New BNF Grammar\n\nHere is the new BNF grammar for global declarations, both functions and\nvariables:\n\n```\n global_declarations : global_declarations \n      | global_declaration global_declarations\n      ;\n\n global_declaration: function_declaration | var_declaration ;\n\n function_declaration: type identifier '(' ')' compound_statement   ;\n\n var_declaration: type identifier_list ';'  ;\n\n type: type_keyword opt_pointer  ;\n \n type_keyword: 'void' | 'char' | 'int' | 'long'  ;\n \n opt_pointer: <empty> | '*' opt_pointer  ;\n \n identifier_list: identifier | identifier ',' identifier_list ;\n```\n\nBoth `function_declaration` and `global_declaration` start with a `type`.\nThis is now a `type_keyword` followed by `opt_pointer` which is zero or more\n'*' tokens. After this, both `function_declaration` and `global_declaration`\nmust be followed by one identifier.\n\nHowever, after the `type`, `var_declaration` is followed by an\n`identifier_list`, which is one or more `identifier`s separated by a ',' token.\nAlso `var_declaration` must end with a ';' token but `function_declaration`\nends with a `compound_statement` and no ';' token.\n\n## New Tokens\n\nWe now have the T_COMMA token for the ',' character in `scan.c`.\n\n## Changes to `decl.c`\n\nWe now convert the above BNF grammar into a set of recursive descent\nfunctions but, as we can do looping, we can turn some of the recursion\ninto internal loops.\n\n### `global_declarations()`\n\nAs there are one or more global declarations, we can loop parsing\neach one. When we run out of tokens, we can leave the loop.\n\n```c\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration and\n      // generate the assembly code for it\n      tree = function_declaration(type);\n      genAST(tree, NOREG, 0);\n    } else {\n\n      // Parse the global variable declaration\n      var_declaration(type);\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n```\n\nKnowing that, for now we only have global variables and functions, we\ncan scan in the type here and the first identifier. Then, we look at\nthe next token. If it's a '(', we call `function_declaration()`. If not,\nwe can assume that it is a  `var_declaration()`. We pass the `type`\nin to both functions.\n\nNow that we are receiving the AST `tree` from `function_declaration()`\nhere, we can generate the code from the AST tree immediately. This code\nwas in `main()` but has now been moved here. `main()` now only has to \ncall `global_declarations()`:\n\n```c\n  scan(&Token);                 // Get the first token from the input\n  genpreamble();                // Output the preamble\n  global_declarations();        // Parse the global declarations\n  genpostamble();               // Output the postamble\n```\n\n### `var_declaration()`\n\nThe parsing of functions is much the same as before, except the code\nto scan the type and identifier are done elsewhere, and we receive the\n`type` as an argument.\n\nThe parsing of variables also loses the type and identifier scanning code.\nWe can add the identifier to the global symbol and generate the assembly\ncode for it. But now we need to add in a loop. If there's a following ',',\nloop back to get the next identifier with the same type. And if there's\na following ';', that's the end of the variable declarations.\n\n```c\n// Parse the declaration of a list of variables.\n// The identifier has been scanned & we have the type\nvoid var_declaration(int type) {\n  int id;\n\n  while (1) {\n    // Text now has the identifier's name.\n    // Add it as a known identifier\n    // and generate its space in assembly\n    id = addglob(Text, type, S_VARIABLE, 0);\n    genglobsym(id);\n\n    // If the next token is a semicolon,\n    // skip it and return.\n    if (Token.token == T_SEMI) {\n      scan(&Token);\n      return;\n    }\n    // If the next token is a comma, skip it,\n    // get the identifier and loop back\n    if (Token.token == T_COMMA) {\n      scan(&Token);\n      ident();\n      continue;\n    }\n    fatal(\"Missing , or ; after identifier\");\n  }\n}\n```\n\n## Not Quite Local Variables\n\n`var_declaration()` can now parse a list of variable declarations, but\nit requires the type and first identifier to be pre-scanned.\n\nThus, I've left the call to `var_declaration()` in `single_statement()`\nin `stmt.c`. Later on, we will modify this to declare local variables.\nBut for now, all of the variables in this example program are globals:\n\n```c\nint   d, f;\nint  *e;\n\nint main() {\n  int a, b, c;\n  b= 3; c= 5; a= b + c * 10;\n  printint(a);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n```\n\n## Testing the Changes\n\nThe above code is our `tests/input16.c`. As always, we can test it:\n\n```\n$ make test16\ncc -o comp1 -g -Wall cg.c decl.c expr.c gen.c main.c misc.c scan.c\n      stmt.c sym.c tree.c types.c\n./comp1 tests/input16.c\ncc -o out out.s lib/printint.c\n./out\n53\n12\n12\n```\n\n\n## Conclusion and What's Next\n\nIn the next part of our compiler writing journey,\nI promise to tackle the issue of adding offsets to pointers. [Next step](../17_Scaling_Offsets/Readme.md)\n"
  },
  {
    "path": "16_Global_Vars/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\nstatic char *dreglist[4] = { \"%r8d\", \"%r9d\", \"%r10d\", \"%r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovzbl\\t%s(\\%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(\\%%rip)\\n\", breglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(\\%%rip)\\n\", dreglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.comm\\t%s,%d,%d\\n\", Gsym[id].name, typesize, typesize);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n"
  },
  {
    "path": "16_Global_Vars/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Gsym[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\tprintint\\n\");\n  fprintf(Outfile, \"\\tnop\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4, 4, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.comm\\t%s,%d,%d\\n\", Gsym[id].name, typesize, typesize);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  }\n  return (r);\n}\n"
  },
  {
    "path": "16_Global_Vars/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\nstatic char *dreglist[4] = { \"r8d\", \"r9d\", \"r10d\", \"r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\tsection\\t.text\\n\"\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r], reglist[r]);\n      fprintf(Outfile, \"\\tmov\\t%s, dword [%s]\\n\", dreglist[r], \n              Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\tcommon\\t%s %d:%d\\n\", Gsym[id].name, typesize, typesize);\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Gsym[id].name);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, word [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n"
  },
  {
    "path": "16_Global_Vars/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n"
  },
  {
    "path": "16_Global_Vars/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// global_declarations : global_declarations\n//      | global_declaration global_declarations\n//      ;\n//\n// global_declaration: function_declaration | var_declaration ;\n//\n// function_declaration: type identifier '(' ')' compound_statement   ;\n//\n// var_declaration: type identifier_list ';'  ; \n//\n// type: type_keyword opt_pointer  ;\n//\n// type_keyword: 'void' | 'char' | 'int' | 'long'  ;\n//\n// opt_pointer: <empty> | '*' opt_pointer  ;\n//\n// identifier_list: identifier | identifier ',' identifier_list ;\n//\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      break;\n    case T_INT:\n      type = P_INT;\n      break;\n    case T_LONG:\n      type = P_LONG;\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'  ;\n//\n// Parse the declaration of a list of variables.\n// The identifier has been scanned & we have the type\nvoid var_declaration(int type) {\n  int id;\n\n  while (1) {\n    // Text now has the identifier's name.\n    // Add it as a known identifier\n    // and generate its space in assembly\n    id = addglob(Text, type, S_VARIABLE, 0);\n    genglobsym(id);\n\n    // If the next token is a semicolon,\n    // skip it and return.\n    if (Token.token == T_SEMI) {\n      scan(&Token);\n      return;\n    }\n    // If the next token is a comma, skip it,\n    // get the identifier and loop back\n    if (Token.token == T_COMMA) {\n      scan(&Token);\n      ident();\n      continue;\n    }\n    fatal(\"Missing , or ; after identifier\");\n  }\n}\n\n//\n// function_declaration: type identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function.\n// The identifier has been scanned & we have the type\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int nameslot, endlabel;\n\n  // Text now has the identifier's name.\n  // Get a label-id for the end label, add the function\n  // to the symbol table, and set the Functionid global\n  // to the function's symbol-id\n  endlabel = genlabel();\n  nameslot = addglob(Text, type, S_FUNCTION, endlabel);\n  Functionid = nameslot;\n\n  // Scan in the parentheses\n  lparen();\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, nameslot));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration and\n      // generate the assembly code for it\n      tree = function_declaration(type);\n      genAST(tree, NOREG, 0);\n    } else {\n\n      // Parse the global variable declaration\n      var_declaration(type);\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "16_Global_Vars/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\nvoid genglobsym(int id);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nvoid cgprintint(int r);\nint cgcall(int r, int id);\nint cgstorglob(int r, int id);\nvoid cgglobsym(int id);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\n\n// expr.c\nstruct ASTnode *funccall(void);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name, int type, int stype, int endlabel);\n\n// decl.c\nvoid var_declaration(int type);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint parse_type(void);\nint type_compatible(int *left, int *right, int onlyright);\nint pointer_to(int type);\nint value_at(int type);\n"
  },
  {
    "path": "16_Global_Vars/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  // Operators\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n  // Structural tokens\n  T_INTLIT, T_SEMI, T_ASSIGN, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_AMPER, T_LOGAND, T_COMMA,\n  // Other keywords\n  T_PRINT, T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ADD = 1, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT,\n  A_IDENT, A_LVIDENT, A_ASSIGN, A_PRINT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n};\n"
  },
  {
    "path": "16_Global_Vars/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a function call with a single expression\n// argument and return its AST\nstruct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined,\n  // then make a leaf node for it. XXX Add structural type test\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Gsym[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n\tn = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n      break;\n\n    case T_IDENT:\n      // This could be a variable or a function call.\n      // Scan in the next token to find out\n      scan(&Token);\n\n      // It's a '(', so a function call\n      if (Token.token == T_LPAREN)\n\treturn (funccall());\n\n      // Not a function call, so reject the new token\n      reject_token(&Token);\n\n      // Check that the variable exists. XXX Add structural type test\n      id = findglob(Text);\n      if (id == -1)\n\tfatals(\"Unknown variable\", Text);\n\n      // Make a leaf AST node for it\n      n = mkastleaf(A_IDENT, Gsym[id].type, id);\n      break;\n\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into an AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int arithop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_PLUS, T_MINUS\n  20, 20,\t\t\t// T_STAR, T_SLASH\n  30, 30,\t\t\t// T_EQ, T_NE\n  40, 40, 40, 40\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*' prefix_expression\n//     | '&' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n    case T_AMPER:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Ensure that it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"& operator must be followed by an identifier\");\n\n      // Now change the operator to A_ADDR and the type to\n      // a pointer to the original type\n      tree->op = A_ADDR;\n      tree->type = pointer_to(tree->type);\n      break;\n    case T_STAR:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's either another deref or an\n      // identifier\n      if (tree->op != A_IDENT && tree->op != A_DEREF)\n\tfatal(\"* operator must be followed by an identifier or *\");\n\n      // Prepend an A_DEREF operation to the tree\n      tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n      break;\n    default:\n      tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  int lefttype, righttype;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Ensure the two types are compatible.\n    lefttype = left->type;\n    righttype = right->type;\n    if (!type_compatible(&lefttype, &righttype, 0))\n      fatal(\"Incompatible types\");\n\n    // Widen either side if required. type vars are A_WIDEN now\n    if (lefttype)\n      left = mkastunary(lefttype, right->type, left, 0);\n    if (righttype)\n      right = mkastunary(righttype, left->type, right, 0);\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon or ')', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "16_Global_Vars/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOREG, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOREG, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\n// and an optional ELSE clause\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOREG, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, the register (if any) that holds\n// the previous rvalue, and the AST op of the parent,\n// generate assembly code recursively.\n// Return the register id with the tree's final value\nint genAST(struct ASTnode *n, int reg, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We now have specific AST node handling at the top\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOREG, n->op);\n      genfreeregs();\n      genAST(n->right, NOREG, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      cgfuncpreamble(n->v.id);\n      genAST(n->left, NOREG, n->op);\n      cgfuncpostamble(n->v.id);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOREG, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, leftreg, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, reg));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue, n->type));\n    case A_IDENT:\n      return (cgloadglob(n->v.id));\n    case A_LVIDENT:\n      return (cgstorglob(reg, n->v.id));\n    case A_ASSIGN:\n      // The work has already been done, return the result\n      return (rightreg);\n    case A_PRINT:\n      // Print the left-child's value\n      // and return no register\n      genprintint(leftreg);\n      genfreeregs();\n      return (NOREG);\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_FUNCCALL:\n      return (cgcall(leftreg, n->v.id));\n    case A_ADDR:\n      return (cgaddress(n->v.id));\n    case A_DEREF:\n      return (cgderef(leftreg, n->left->type));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "16_Global_Vars/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n"
  },
  {
    "path": "16_Global_Vars/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n  Globs = 0;\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nint main(int argc, char *argv[]) {\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n  // For now, ensure that void printint() is defined\n  addglob(\"printint\", P_CHAR, S_FUNCTION, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  return (0);\n}\n"
  },
  {
    "path": "16_Global_Vars/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "16_Global_Vars/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'p':\n      if (!strcmp(s, \"print\"))\n\treturn (T_PRINT);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tfatalc(\"Unrecognised character\", c);\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "16_Global_Vars/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: print_statement\n//      |     declaration\n//      |     assignment_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n// print_statement: 'print' expression ';'  ;\n//\nstatic struct ASTnode *print_statement(void) {\n  struct ASTnode *tree;\n  int lefttype, righttype;\n\n  // Match a 'print' as the first token\n  match(T_PRINT, \"print\");\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure the two types are compatible.\n  lefttype = P_INT;\n  righttype = tree->type;\n  if (!type_compatible(&lefttype, &righttype, 0))\n    fatal(\"Incompatible types\");\n\n  // Widen the tree if required. \n  if (righttype)\n    tree = mkastunary(righttype, P_INT, tree, 0);\n\n  // Make an print AST tree\n  tree = mkastunary(A_PRINT, P_NONE, tree, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// assignment_statement: identifier '=' expression ';'   ;\n//\n// Parse an assignment statement and return its AST\nstatic struct ASTnode *assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int lefttype, righttype;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // This could be a variable or a function call.\n  // If next token is '(', it's a function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // Not a function call, on with an assignment then!\n  // Check the identifier has been defined then make a leaf node for it\n  // XXX Add structural type test\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared variable\", Text);\n  }\n  right = mkastleaf(A_LVIDENT, Gsym[id].type, id);\n\n  // Ensure we have an equals sign\n  match(T_ASSIGN, \"=\");\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Ensure the two types are compatible.\n  lefttype = left->type;\n  righttype = right->type;\n  if (!type_compatible(&lefttype, &righttype, 1))\n    fatal(\"Incompatible types\");\n\n  // Widen the left if required.\n  if (lefttype)\n    left = mkastunary(lefttype, right->type, left, 0);\n\n  // Make an assignment AST tree\n  tree = mkastnode(A_ASSIGN, P_INT, left, NULL, right, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n  int returntype, functype;\n\n  // Can't return a value if function returns P_VOID\n  if (Gsym[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  returntype = tree->type;\n  functype = Gsym[Functionid].type;\n  if (!type_compatible(&returntype, &functype, 1))\n    fatal(\"Incompatible types\");\n\n  // Widen the left if required.\n  if (returntype)\n    tree = mkastunary(returntype, functype, tree, 0);\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n    case T_PRINT:\n      return (print_statement());\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration.\n      // XXX: These are globals at present.\n      type = parse_type();\n      ident();\n      var_declaration(type);\n      return (NULL);\t\t// No AST generated here\n    case T_IDENT:\n      return (assignment_statement());\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_PRINT || tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "16_Global_Vars/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table.\n// Also set up its type and structural type.\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int endlabel) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  Gsym[y].type = type;\n  Gsym[y].stype = stype;\n  Gsym[y].endlabel = endlabel;\n  return (y);\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input01.c",
    "content": "void main()\n{ printint(12 * 3);\n  printint(18 - 2 * 4);\n  printint(1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input02.c",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printint(fred + jim);\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input03.c",
    "content": "void main()\n{\n  int x;\n  x= 1;     printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input04.c",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  printint(x);\n  x= 7 <= 9; printint(x);\n  x= 7 != 9; printint(x);\n  x= 7 == 7; printint(x);\n  x= 7 >= 7; printint(x);\n  x= 7 <= 7; printint(x);\n  x= 9 > 7;  printint(x);\n  x= 9 >= 7; printint(x);\n  x= 9 != 7; printint(x);\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input05.c",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printint(i);\n  } else {\n    printint(j);\n  }\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input06.c",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printint(i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input07.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input08.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input09.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printint(2 * b - a); }\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input10.c",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; printint(j);\n  i= 10; printint(i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 2; j= j + 1) { printint(j); }\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input11.c",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; printint(i);\n  j= 20; printint(j);\n  k= 30; printint(k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 4; j= j + 1) { printint(j); }\n  for (k= 1;   k <= 5; k= k + 1) { printint(k); }\n  return(i);\n  printint(12345);\n  return(3);\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input12.c",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printint(x);\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input13.c",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input14.c",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input15.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printint(a);\n  b= &a; c= *b; printint(c);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/input16.c",
    "content": "int   d, f;\nint  *e;\n\nint main() {\n  int a, b, c;\n  b= 3; c= 5; a= b + c * 10;\n  printint(a);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "16_Global_Vars/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" ]\n   then\n     cc -o out $i ../lib/printint.c\n     ./out > out.$i\n     rm -f out\n   fi\ndone\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "16_Global_Vars/tests/out.input16.c",
    "content": "53\n12\n12\n"
  },
  {
    "path": "16_Global_Vars/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "16_Global_Vars/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -Wall -o out out.o ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "16_Global_Vars/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n"
  },
  {
    "path": "16_Global_Vars/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given two primitive types,\n// return true if they are compatible,\n// false otherwise. Also return either\n// zero or an A_WIDEN operation if one\n// has to be widened to match the other.\n// If onlyright is true, only widen left to right.\nint type_compatible(int *left, int *right, int onlyright) {\n  int leftsize, rightsize;\n\n  // Same types, they are compatible\n  if (*left == *right) {\n    *left = *right = 0;\n    return (1);\n  }\n  // Get the sizes for each type\n  leftsize = genprimsize(*left);\n  rightsize = genprimsize(*right);\n\n  // Types with zero size are not\n  // not compatible with anything\n  if ((leftsize == 0) || (rightsize == 0))\n    return (0);\n\n  // Widen types as required\n  if (leftsize < rightsize) {\n    *left = A_WIDEN;\n    *right = 0;\n    return (1);\n  }\n  if (rightsize < leftsize) {\n    if (onlyright)\n      return (0);\n    *left = 0;\n    *right = A_WIDEN;\n    return (1);\n  }\n  // Anything remaining is the same size\n  // and thus compatible\n  *left = *right = 0;\n  return (1);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOID:\n      newtype = P_VOIDPTR;\n      break;\n    case P_CHAR:\n      newtype = P_CHARPTR;\n      break;\n    case P_INT:\n      newtype = P_INTPTR;\n      break;\n    case P_LONG:\n      newtype = P_LONGPTR;\n      break;\n    default:\n      fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOIDPTR:\n      newtype = P_VOID;\n      break;\n    case P_CHARPTR:\n      newtype = P_CHAR;\n      break;\n    case P_INTPTR:\n      newtype = P_INT;\n      break;\n    case P_LONGPTR:\n      newtype = P_LONG;\n      break;\n    default:\n      fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g -Wall $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g -Wall $(SRCN)\n\ncomp1arm: $(ARMSRCS)\n\tcc -o comp1arm -g -Wall $(ARMSRCS)\n\tcp comp1arm comp1\n\nclean:\n\trm -f comp1 comp1arm compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: comp1arm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\ntest16: comp1 tests/input16.c lib/printint.c\n\t./comp1 tests/input16.c\n\tcc -o out out.s lib/printint.c\n\t./out\n\narmtest16: comp1arm tests/input16.c lib/printint.c\n\t./comp1 tests/input16.c\n\tcc -o out out.s lib/printint.c\n\t./out\n\ntest16n: compn tests/input16.c lib/printint.c\n\t./compn tests/input16.c\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out lib/printint.c out.o\n\t./out\n"
  },
  {
    "path": "17_Scaling_Offsets/Readme.md",
    "content": "# Part 17: Better Type Checking and Pointer Offsets\n\nA couple of parts ago, I introduced pointers and implemented some code to\ncheck type compatibility. At the time, I realised that, for code like:\n\n```c\n  int   c;\n  int  *e;\n\n  e= &c + 1;\n```\n\nthe addition of one to the pointer calculated by `&c` would need to be\nconverted into the size of `c`, to ensure we skip to the next `int`\nin memory after `c`. In other words, we would have to scale the integer.\n\nWe need to do this for pointer, and later on we will need to do this for\narrays. Consider the code:\n\n```c\n  int list[10];\n  int x= list[3];\n```\n\nTo do this, we need to find the base address of `list[]`, then add on\nthree times the size of `int` to find the element at index position 3.\n\nAt the time, I'd written a function in `types.c` called `type_compatible()`\nto determine if two types were compatible, and to indicate if we needed to\n\"widen\" a small integer type so that it was the same size as a larger integer\ntype. This widening, though, was performed elsewhere. In fact, it ended up\nbeing done in three places in the compiler.\n\n## A Replacement for `type_compatible()`\n\nIf `type_compatible()` indicated so, we would A_WIDEN a tree to match\na larger integer type. Now we need to A_SCALE a tree so that its value is\nscaled by the size of a type. And I want to refactor the duplicate\nwidening code.\n\nTo this end, I've thrown out `type_compatible()` and replaced it. This took\nquite a bit of thinking, and I probably will have to tweak or extend it again.\nLet's look at the design.\n\nThe existing `type_compatible()`:\n + took two type values as arguments, plus an optional direction,\n + returned true if the types were compatible,\n + returned A_WIDEN on the left or right if either side needed to\n   be widened,\n + didn't actually add the A_WIDEN node to the tree,\n + returned false if the types were not compatible, and\n + didn't handle pointer types\n\nNow let's look at the use cases for type comparisons:\n\n + when performing a binary operation on two expressions, are their\n   types compatible and do we need to widen or scale one?\n + when doing a `print` statement, is the expression an integer and\n   does it need widening?\n + when doing an assignment statement, does the expression need widening\n   and does it match the lvalue type?\n + when doing a `return` statement, does the expression need widening\n   and does it match the return type of the function?\n\nIn only one of these use cases do we have two expressions. Therefore, I've\nchosen to write a new function that takes one AST tree and the type we\nwant it to become. For the binary operation use case, we will call it\ntwice and see what happens for each call.\n\n## Introducing `modify_type()`\n\n`modify_type()` in `types.c` is the replacement code for `type_compatible()`.\nThe API for the function is:\n\n```c\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n```\n\nQuestion: why do we need whatever binary operation is being performed on\nthe tree and some other tree? The answer is that we can only add to or\nsubtract from pointers. We can't do anything else, e.g.\n\n```c\n  int x;\n  int *ptr;\n\n  x= *ptr;\t   // OK\n  x= *(ptr + 2);   // Two ints up from where ptr is pointing\n  x= *(ptr * 4);   // Does not make sense\n  x= *(ptr / 13);  // Does not make sense either\n```\n\nHere is the code for now. There are lots of specific tests, and at present\nI can't see a way to rationalise all the possible tests. Also, it will need\nto be extended later.\n\n```c\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype) return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize) return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize) return (mkastunary(A_WIDEN, rtype, tree, 0));\n  }\n\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype) return (tree);\n  }\n\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1) \n        return (mkastunary(A_SCALE, rtype, tree, rsize));\n    }\n  }\n\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n```\n\nThe code to add the AST A_WIDEN and A_SCALE operations are now done\nhere in one place only. The A_WIDEN operation converts the child's\ntype to the parent's type. The A_SCALE operation multiplies the child's\nvalue by the size which is store in the new `struct ASTnode` union field\n(in `defs.h`):\n\n```c\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  ...\n  union {\n    int size;                   // For A_SCALE, the size to scale by\n  } v;\n};\n```\n\n## Using the New `modify_type()` API\n\nWith this new API, we can remove the duplicated code to A_WIDEN which is\nin `stmt.c` and `expr.c`. However, this new function only takes one tree.\nThis is fine when we indeed only have one tree. There are three calls now\nto `modify_type()` in `stmt.c`. They are all similar, so here is the one\nfrom  `assignment_statement()`:\n\n```c\n  // Make the AST node for the assignment lvalue\n  right = mkastleaf(A_LVIDENT, Gsym[id].type, id);\n\n  ...\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Ensure the two types are compatible.\n  left = modify_type(left, right->type, 0);\n  if (left == NULL) fatal(\"Incompatible expression in assignment\");\n```\n\nwhich is so much cleaner than the code we had before.\n\n### And in `binexpr()` ...\n\nBut in `binexpr()` in `expr.c`, we now need to combine two AST trees\nwith a binary operations like addition, multiplication etc. Here, we\ntry to `modify_type()` each tree with the other tree's type. Now, one\nmay widen: this also implies that the other will fail and return NULL.\nThus, we can't just see if one result from `modify_type()` is NULL: we\nneed to see both be NULL to assume a type incompatibility. Here's the\nnew comparison code in `binexpr()`:\n\n```c\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  ...\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n  tokentype = Token.token;\n\n  ...\n  // Recursively call binexpr() with the\n  // precedence of our token to build a sub-tree\n  right = binexpr(OpPrec[tokentype]);\n\n  // Ensure the two types are compatible by trying\n  // to modify each tree to match the other's type.\n  ASTop = arithop(tokentype);\n  ltemp = modify_type(left, right->type, ASTop);\n  rtemp = modify_type(right, left->type, ASTop);\n  if (ltemp == NULL && rtemp == NULL)\n    fatal(\"Incompatible types in binary expression\");\n\n  // Update any trees that were widened or scaled\n  if (ltemp != NULL) left = ltemp;\n  if (rtemp != NULL) right = rtemp;\n```\n\nThe code is a little bit messy but no more that what was previously there,\nand it now deals with A_SCALE as well as A_WIDEN.\n\n## Performing the Scaling\n\nWe have added the A_SCALE to the list of AST node operations in `defs.h`.\nNow we need to implement it.\n\nAs I mentioned before, the A_SCALE operation\nmultiplies the child's value by the size which is store in the new `struct\nASTnode` union field. For all of our integer types, this will be a multiple\nof two. Because of this fact, we can multiply the child's value with a\nshift left of a certain number of bits.\n\nLater on, we will have structs that have a size which isn't a power of two.\nSo we can do a shift optimisation when the scale factor is suitable, but\nwe also need to implement a multiply for a more general scale factor.\n\nHere is the new code that does this in `genAST()` in `gen.c`:\n\n```c\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->v.size) {\n        case 2: return(cgshlconst(leftreg, 1));\n        case 4: return(cgshlconst(leftreg, 2));\n        case 8: return(cgshlconst(leftreg, 3));\n        default:\n          // Load a register with the size and\n          // multiply the leftreg by this size\n          rightreg= cgloadint(n->v.size, P_INT);\n          return (cgmul(leftreg, rightreg));\n```\n\n## Shifting Left in x86-64 Code\n\nWe now need a `cgshlconst()` function to shift a register value left\nby a constant. When we add the C '<<' operator later, I will write a\nmore general shift left function. For now, we can use the `salq` instruction\nwith an integer literal value:\n\n```c\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return(r);\n}\n```\n\n## Our Test Program that Doesn't Work\n\nMy test program for the scaling functionality is `tests/input16.c`:\n\n```c\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printint(c);\n  e= &c + 1; f= *e; printint(f);\n  return(0);\n}\n```\n\nI was hoping that `d` would be placed immediately after `c` by the assembler\nwhen we generate these assembly directives:\n\n```\n        .comm   c,1,1\n        .comm   d,4,4\n```\n\nBut when I compiled the assembly output and checked, they were not adjacent:\n\n```\n$ cc -o out out.s lib/printint.c\n$ nm -n out | grep 'B '\n0000000000201018 B d\n0000000000201020 B b\n0000000000201028 B f\n0000000000201030 B e\n0000000000201038 B c\n```\n\n`d` actually comes *before* `c`! I had to work out a way to ensure\nthe adjacency, so I looked at the code that *SubC* generates here,\nand changed our compiler to now generate this:\n\n```\n        .data\n        .globl  c\nc:      .long   0\t# Four byte integer\n        .globl  d\nd:      .long   0\n        .globl  e\ne:      .quad   0\t# Eight byte pointer\n        .globl  f\nf:      .long   0\n```\n\nNow when we run our `input16.c` test, `e= &c + 1; f= *e;` gets the address\nof the integer one up from `c` and stores that integer's value in `f`. As\nwe declared:\n\n```c\n  int   c;\n  int   d;\n  ...\n  c= 12; d=18; printint(c);\n  e= &c + 1; f= *e; printint(f);\n\n```\n\nwe will print out both numbers:\n\n```\ncc -o comp1 -g -Wall cg.c decl.c expr.c gen.c main.c misc.c\n      scan.c stmt.c sym.c tree.c types.c\n./comp1 tests/input16.c\ncc -o out out.s lib/printint.c\n./out\n12\n18\n```\n\n## Conclusion and What's Next\n\nI feel  a lot happier with the code that converts between types. Behind\nthe scenes, I wrote some test code that supplied all possible type\nvalues to `modify_type()`, as well as a binary operation and zero for\nthe operation. I eyeballed the output and it seems to be what I want.\nOnly time will tell.\n\nIn the next part of our compiler writing journey,\nI don't know what I will do! [Next step](../18_Lvalues_Revisited/Readme.md)\n"
  },
  {
    "path": "17_Scaling_Offsets/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\nstatic char *dreglist[4] = { \"%r8d\", \"%r9d\", \"%r10d\", \"%r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovzbl\\t%s(\\%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(\\%%rip)\\n\", breglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(\\%%rip)\\n\", dreglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Gsym[id].name);\n  switch(typesize) {\n    case 1: fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Gsym[id].name); break;\n    case 4: fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Gsym[id].name); break;\n    case 8: fprintf(Outfile, \"%s:\\t.quad\\t0\\n\", Gsym[id].name); break;\n    default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Gsym[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\tprintint\\n\");\n  fprintf(Outfile, \"\\tnop\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4, 4, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Gsym[id].name);\n  switch(typesize) {\n    case 1: fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Gsym[id].name); break;\n    case 4: fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Gsym[id].name); break;\n    default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  }\n  return (r);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\nstatic char *dreglist[4] = { \"r8d\", \"r9d\", \"r10d\", \"r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\tsection\\t.text\\n\"\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r], reglist[r]);\n      fprintf(Outfile, \"\\tmov\\t%s, dword [%s]\\n\", dreglist[r], \n              Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", Gsym[id].name);\n  switch(typesize) {\n    case 1: fprintf(Outfile, \"%s:\\tdb\\t0\\n\", Gsym[id].name); break;\n    case 4: fprintf(Outfile, \"%s:\\tdd\\t0\\n\", Gsym[id].name); break;\n    case 8: fprintf(Outfile, \"%s:\\tdq\\t0\\n\", Gsym[id].name); break;\n    default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Gsym[id].name);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, word [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n"
  },
  {
    "path": "17_Scaling_Offsets/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      break;\n    case T_INT:\n      type = P_INT;\n      break;\n    case T_LONG:\n      type = P_LONG;\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'  ;\n//\n// Parse the declaration of a variable.\n// The identifier has been scanned & we have the type\nvoid var_declaration(int type) {\n  int id;\n\n  // Text now has the identifier's name.\n  // Add it as a known identifier\n  // and generate its space in assembly\n  id = addglob(Text, type, S_VARIABLE, 0);\n  genglobsym(id);\n  // Get the trailing semicolon\n  semi();\n}\n\n//\n// function_declaration: type identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function.\n// The identifier has been scanned & we have the type\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int nameslot, endlabel;\n\n  // Text now has the identifier's name.\n  // Get a label-id for the end label, add the function\n  // to the symbol table, and set the Functionid global\n  // to the function's symbol-id\n  endlabel = genlabel();\n  nameslot = addglob(Text, type, S_FUNCTION, endlabel);\n  Functionid = nameslot;\n\n  // Scan in the parentheses\n  lparen();\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, nameslot));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n       // Parse the function declaration and\n       // generate the assembly code for it\n       tree = function_declaration(type);\n       genAST(tree, NOREG, 0);\n    } else {\n\n       // Parse the global variable declaration\n       var_declaration(type);\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\nvoid genglobsym(int id);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nvoid cgprintint(int r);\nint cgcall(int r, int id);\nint cgstorglob(int r, int id);\nvoid cgglobsym(int id);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\n\n// expr.c\nstruct ASTnode *funccall(void);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name, int type, int stype, int endlabel);\n\n// decl.c\nvoid var_declaration(int type);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint parse_type(void);\nint pointer_to(int type);\nint value_at(int type);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "17_Scaling_Offsets/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  // Operators\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n  // Structural tokens\n  T_INTLIT, T_SEMI, T_ASSIGN, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_AMPER, T_LOGAND,\n  // Other keywords\n  T_PRINT, T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ADD = 1, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT,\n  A_IDENT, A_LVIDENT, A_ASSIGN, A_PRINT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n};\n"
  },
  {
    "path": "17_Scaling_Offsets/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a function call with a single expression\n// argument and return its AST\nstruct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined,\n  // then make a leaf node for it. XXX Add structural type test\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Gsym[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n\tn = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n      break;\n\n    case T_IDENT:\n      // This could be a variable or a function call.\n      // Scan in the next token to find out\n      scan(&Token);\n\n      // It's a '(', so a function call\n      if (Token.token == T_LPAREN)\n\treturn (funccall());\n\n      // Not a function call, so reject the new token\n      reject_token(&Token);\n\n      // Check that the variable exists. XXX Add structural type test\n      id = findglob(Text);\n      if (id == -1)\n\tfatals(\"Unknown variable\", Text);\n\n      // Make a leaf AST node for it\n      n = mkastleaf(A_IDENT, Gsym[id].type, id);\n      break;\n\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into an AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int arithop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_PLUS, T_MINUS\n  20, 20,\t\t\t// T_STAR, T_SLASH\n  30, 30,\t\t\t// T_EQ, T_NE\n  40, 40, 40, 40\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*' prefix_expression\n//     | '&' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n    case T_AMPER:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Ensure that it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"& operator must be followed by an identifier\");\n\n      // Now change the operator to A_ADDR and the type to\n      // a pointer to the original type\n      tree->op = A_ADDR;\n      tree->type = pointer_to(tree->type);\n      break;\n    case T_STAR:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's either another deref or an\n      // identifier\n      if (tree->op != A_IDENT && tree->op != A_DEREF)\n\tfatal(\"* operator must be followed by an identifier or *\");\n\n      // Prepend an A_DEREF operation to the tree\n      tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n      break;\n    default:\n      tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN)\n    return (left);\n\n  // While the precedence of this token is\n  // more than that of the previous token precedence\n  while (op_precedence(tokentype) > ptp) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Ensure the two types are compatible by trying\n    // to modify each tree to match the other's type.\n    ASTop = arithop(tokentype);\n    ltemp = modify_type(left, right->type, ASTop);\n    rtemp = modify_type(right, left->type, ASTop);\n    if (ltemp == NULL && rtemp == NULL)\n      fatal(\"Incompatible types in binary expression\");\n    if (ltemp != NULL)\n      left = ltemp;\n    if (rtemp != NULL)\n      right = rtemp;\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(arithop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon or ')', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN)\n      return (left);\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOREG, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOREG, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\n// and an optional ELSE clause\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  // We cheat by sending the Lfalse label as a register.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOREG, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, the register (if any) that holds\n// the previous rvalue, and the AST op of the parent,\n// generate assembly code recursively.\n// Return the register id with the tree's final value\nint genAST(struct ASTnode *n, int reg, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We now have specific AST node handling at the top\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOREG, n->op);\n      genfreeregs();\n      genAST(n->right, NOREG, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      cgfuncpreamble(n->v.id);\n      genAST(n->left, NOREG, n->op);\n      cgfuncpostamble(n->v.id);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOREG, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, leftreg, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, reg));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue, n->type));\n    case A_IDENT:\n      return (cgloadglob(n->v.id));\n    case A_LVIDENT:\n      return (cgstorglob(reg, n->v.id));\n    case A_ASSIGN:\n      // The work has already been done, return the result\n      return (rightreg);\n    case A_PRINT:\n      // Print the left-child's value\n      // and return no register\n      genprintint(leftreg);\n      genfreeregs();\n      return (NOREG);\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_FUNCCALL:\n      return (cgcall(leftreg, n->v.id));\n    case A_ADDR:\n      return (cgaddress(n->v.id));\n    case A_DEREF:\n      return (cgderef(leftreg, n->left->type));\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->v.size) {\n\tcase 2: return(cgshlconst(leftreg, 1));\n\tcase 4: return(cgshlconst(leftreg, 2));\n\tcase 8: return(cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n          rightreg= cgloadint(n->v.size, P_INT);\n          return (cgmul(leftreg, rightreg));\n      }\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n  Globs = 0;\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nint main(int argc, char *argv[]) {\n\n  if (argc != 2)\n    usage(argv[0]);\n\n  init();\n\n  // Open up the input file\n  if ((Infile = fopen(argv[1], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[1], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n  // For now, ensure that void printint() is defined\n  addglob(\"printint\", P_CHAR, S_FUNCTION, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  return (0);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'p':\n      if (!strcmp(s, \"print\"))\n\treturn (T_PRINT);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tfatalc(\"Unrecognised character\", c);\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: print_statement\n//      |     declaration\n//      |     assignment_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n// print_statement: 'print' expression ';'  ;\n//\nstatic struct ASTnode *print_statement(void) {\n  struct ASTnode *tree;\n\n  // Match a 'print' as the first token\n  match(T_PRINT, \"print\");\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure the two types are compatible.\n  tree = modify_type(tree, P_INT, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to print\");\n\n  // Make an print AST tree\n  tree = mkastunary(A_PRINT, P_NONE, tree, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// assignment_statement: identifier '=' expression ';'   ;\n//\n// Parse an assignment statement and return its AST\nstatic struct ASTnode *assignment_statement(void) {\n  struct ASTnode *left, *right, *tree;\n  int id;\n\n  // Ensure we have an identifier\n  ident();\n\n  // This could be a variable or a function call.\n  // If next token is '(', it's a function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // Not a function call, on with an assignment then!\n  // Check the identifier has been defined then make a leaf node for it\n  // XXX Add structural type test\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared variable\", Text);\n  }\n  right = mkastleaf(A_LVIDENT, Gsym[id].type, id);\n\n  // Ensure we have an equals sign\n  match(T_ASSIGN, \"=\");\n\n  // Parse the following expression\n  left = binexpr(0);\n\n  // Ensure the two types are compatible.\n  left = modify_type(left, right->type, 0);\n  if (left == NULL)\n    fatal(\"Incompatible expression in assignment\");\n\n  // Make an assignment AST tree\n  tree = mkastnode(A_ASSIGN, P_INT, left, NULL, right, 0);\n\n  // Return the AST\n  return (tree);\n}\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Gsym[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Gsym[Functionid].type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to print\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n    case T_PRINT:\n      return (print_statement());\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration.\n      // XXX: These are globals at present.\n      type = parse_type();\n      ident();\n      var_declaration(type);\n      return (NULL);\t\t// No AST generated here\n    case T_IDENT:\n      return (assignment_statement());\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_PRINT || tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table.\n// Also set up its type and structural type.\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int endlabel) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  Gsym[y].type = type;\n  Gsym[y].stype = stype;\n  Gsym[y].endlabel = endlabel;\n  return (y);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input01.c",
    "content": "void main()\n{ printint(12 * 3);\n  printint(18 - 2 * 4);\n  printint(1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input02.c",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printint(fred + jim);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input03.c",
    "content": "void main()\n{\n  int x;\n  x= 1;     printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input04.c",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  printint(x);\n  x= 7 <= 9; printint(x);\n  x= 7 != 9; printint(x);\n  x= 7 == 7; printint(x);\n  x= 7 >= 7; printint(x);\n  x= 7 <= 7; printint(x);\n  x= 9 > 7;  printint(x);\n  x= 9 >= 7; printint(x);\n  x= 9 != 7; printint(x);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input05.c",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printint(i);\n  } else {\n    printint(j);\n  }\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input06.c",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printint(i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input07.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input08.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input09.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printint(2 * b - a); }\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input10.c",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; printint(j);\n  i= 10; printint(i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 2; j= j + 1) { printint(j); }\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input11.c",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; printint(i);\n  j= 20; printint(j);\n  k= 30; printint(k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 4; j= j + 1) { printint(j); }\n  for (k= 1;   k <= 5; k= k + 1) { printint(k); }\n  return(i);\n  printint(12345);\n  return(3);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input12.c",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printint(x);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input13.c",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input14.c",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input15.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printint(a);\n  b= &a; c= *b; printint(c);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/input16.c",
    "content": "int   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printint(c);\n  e= &c + 1; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" ]\n   then\n     cc -o out $i ../lib/printint.c\n     ./out > out.$i\n     rm -f out\n   fi\ndone\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "17_Scaling_Offsets/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -Wall -o out out.o ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "17_Scaling_Offsets/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n"
  },
  {
    "path": "17_Scaling_Offsets/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  if (type == P_CHAR || type == P_INT || type == P_LONG)\n    return (1);\n  return (0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  if (type == P_VOIDPTR || type == P_CHARPTR ||\n      type == P_INTPTR || type == P_LONGPTR)\n    return (1);\n  return (0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOID:\n      newtype = P_VOIDPTR;\n      break;\n    case P_CHAR:\n      newtype = P_CHARPTR;\n      break;\n    case P_INT:\n      newtype = P_INTPTR;\n      break;\n    case P_LONG:\n      newtype = P_LONGPTR;\n      break;\n    default:\n      fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOIDPTR:\n      newtype = P_VOID;\n      break;\n    case P_CHARPTR:\n      newtype = P_CHAR;\n      break;\n    case P_INTPTR:\n      newtype = P_INT;\n      break;\n    case P_LONGPTR:\n      newtype = P_LONG;\n      break;\n    default:\n      fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1) \n\treturn (mkastunary(A_SCALE, rtype, tree, rsize));\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g -Wall $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g -Wall $(SRCN)\n\ncomp1arm: $(ARMSRCS)\n\tcc -o comp1arm -g -Wall $(ARMSRCS)\n\tcp comp1arm comp1\n\nclean:\n\trm -f comp1 comp1arm compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: comp1arm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\ntest17: comp1 tests/input17.c lib/printint.c\n\t./comp1 tests/input17.c\n\tcc -o out out.s lib/printint.c\n\t./out\n\narmtest17: comp1arm tests/input17.c lib/printint.c\n\t./comp1 tests/input17.c\n\tcc -o out out.s lib/printint.c\n\t./out\n\ntest17n: compn tests/input17.c lib/printint.c\n\t./compn tests/input17.c\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out lib/printint.c out.o\n\t./out\n"
  },
  {
    "path": "18_Lvalues_Revisited/Readme.md",
    "content": "# Part 18: Lvalues and Rvalues Revisited\n\nAs this is work in progress with no design document to guide me,\noccasionally I need to remove code that I've already written and\nrewrite it to make it more general, or to fix shortcomings. That's\nthe case for this part of the journey.\n\nWe added our initial support for pointers in part 15 so that we could\nwrite code line this:\n\n```c\n  int  x;\n  int *y;\n  int  z;\n  x= 12; y= &x; z= *y;\n```\n\nThat's all fine and good, but I knew that we would eventually have to\nsupport the use of pointers on the left-hand side of assignment statements,\ne.g.\n\n```c\n  *y = 14;\n```\n\nTo do this, we have to revisit the topic of\n[lvalues and rvalues](https://en.wikipedia.org/wiki/Value_(computer_science)#lrvalue).\nTo revise, an *lvalue* is a value that is tied to a specific location, whereas\nan *rvalue* is a value that isn't. Lvalues are persistent in that we can\nretrieve their value in future instructions. Rvalues, on the other\nhand, are evanescent: we can discard them once their use is finished.\n\n### Examples of Rvalues and Lvalues\n\nAn example of an rvalue is an integer literal, e.g. 23. We can use it\nin an expression and then discard it afterwards. Examples of lvalues\nare locations in memory which we can *store into*, such as:\n\n```\n   a            Scalar variable a\n   b[0]         Element zero of array b\n   *c           The location that pointer c points to\n   (*d)[0]      Element zero of the array that d points to\n```\n\nAs I mentioned before, the names *lvalue* and *rvalue* come from the\ntwo sides of an assignment statement: lvalues are on the left, rvalues\nare on the right.\n\n## Extending Our Notion of Lvalues\n\nRight now, the compiler treats nearly everything as an rvalue. For\nvariables, it retrieves the value from the variable's location. Our\nonly nod to the concept of the lvalue is to mark identifiers on the\nleft of an assignment as an A_LVIDENT. We manually deal with this in\n`genAST()`:\n\n```c\n    case A_IDENT:\n      return (cgloadglob(n->v.id));\n    case A_LVIDENT:\n      return (cgstorglob(reg, n->v.id));\n    case A_ASSIGN:\n      // The work has already been done, return the result\n      return (rightreg);\n```\n\nwhich we use for statements like `a= b;`. But now we need to mark\nmore than just identifiers on the left-hand side of an assignment\nas lvalues.\n\nIt's also important to make it easy to generate assembly code in\nthe process. While I was writing this part, I tried the idea of\nprepending a \"A_LVALUE\" AST node as the parent to a tree, to\ntell the code generator to output the lvalue version of the code for it\ninstead of the rvalue version. But this turned out to be too late:\nthe sub-tree was already evaluated and rvalue code for it had already\nbeen generated.\n\n### Yet Another AST Node Change\n\nI'm loath to keep adding more fields to the AST node, but this is\nwhat I ended up doing. We now have a field to indicate if the node\nshould generate lvalue code or rvalue code:\n\n```c\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  ...\n};\n```\n\nThe `rvalue` field only holds one bit of information; later on, if I need\nto store other booleans, I will be able to use this as a bitfield.\n\nQuestion: why did I make the field indicate the \"rvalue\"ness of the node\nand not the \"lvalue\"ness? After all, most of the nodes in our AST trees\nwill hold rvalues and not lvalues. While I was reading Nils Holm's book\non SubC, I read this line:\n\n> Since an indirection cannot be reversed later, the parser assumes each\n  partial expression to be an lvalue.\n\nConsider the parser working on the statement `b = a + 2`. After parsing\nthe `b` identifier, we cannot yet tell is this is an lvalue or an rvalue.\nIt's not until we hit the `=` token that we can conclude that it's an\nlvalue.\n\nAlso, the C language allows assignments as expressions, so we can also\nwrite `b = c = a + 2`. Again, when we parse the `a` identifier, we\ncan't tell if it's an lvalue or an rvalue until we parse the next token.\n\nTherefore, I chose to assume each AST node to be an lvalue by default.\nOnce we can definitely tell if a node is rvalue, we can then set the\n`rvalue` field to indicate this.\n\n## Assignment Expressions\n\nI also mentioned that the C language allows assignments as expressions.\nNow that we have a clear lvalue/rvalue distinction, we can shift the\nparsing of assignments as statements and move the code into the\nexpression parser. I'll cover this later.\n\nIt's now time to see what was done to the compiler code base to make\nthis all happen. As always, we start with the tokens and the scanner\nfirst.\n\n## Token and Scanning Changes\n\nWe have no new tokens or new keywords this time. But there is a change\nwhich affects the token code. The `=` is now a binary operator with an\nexpression on each side, so we need to integrate it with the other\nbinary operators.\n\nAccording to [this list of C operators](https://en.cppreference.com/w/c/language/operator_precedence), the `=` operator has much lower precedence than\n`+` or `-`. We there need to rearrange our list of operators and their\nprecedences. In `defs.h`:\n\n```c\n// Token types\nenum {\n  T_EOF,\n  // Operators\n  T_ASSIGN,\n  T_PLUS, T_MINUS, ...\n```\n\nIn `expr.c`, we need to update the code that holds the precedences for\nour binary operators:\n\n```c\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n   0, 10,                       // T_EOF,  T_ASSIGN\n  20, 20,                       // T_PLUS, T_MINUS\n  30, 30,                       // T_STAR, T_SLASH\n  40, 40,                       // T_EQ, T_NE\n  50, 50, 50, 50                // T_LT, T_GT, T_LE, T_GE\n};\n```\n\n## Changes to the Parser\n\nNow we have to remove the parsing of assignments as statements and\nmake them into expressions. I also took the liberty of removing\nthe \"print\" statement from the language, as we can now call `printint()`.\nSo, in `stmt.c`, I've removed both `print_statement()` and\n`assignment_statement()`. \n\n> I also removed the T_PRINT and 'print'\n  keywords from the language. And now that our concept of lvalues and\n  rvalues are different, I also removed the A_LVIDENT AST node type.\n\nFor now, the statement parser in `single_statement()` in `stmt.c`\nassumes that what's coming up next is an expression if it doesn't\nrecognise the first token:\n\n```c\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n    ...\n    default:\n    // For now, see if this is an expression.\n    // This catches assignment statements.\n    return (binexpr(0));\n  }\n}\n```\n\nThis does mean that `2+3;` will be treated as a legal statement for now.\nWe will fix this later. And in `compound_statement()` we also ensure\nthat the expression is followed by a semicolon:\n\n```c\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n                         tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n```\n\n## Expression Parsing\n\nYou might think that, now that `=` is marked as a binary expression\noperator and we have set its precedence, that we are all done. Not so!\nThere are two things we have to worry about:\n\n1. We need to generate the assembly code for the right-hand rvalue\n   before the code for the left-hand lvalue. We used to do this in\n   the statement parser, and we'll have to do this in the expression\n   parser.\n2. Assignment expressions are *right associative*: the operator binds\n   more tightly to the expression on the right than to the left.\n\nWe haven't touched right associativity before. Let's look at an example.\nConsider the expression `2 + 3 + 4`. We can happily parse this from\nleft to right and build the AST tree:\n\n```\n      +\n     / \\\n    +   4\n   / \\\n  2   3\n```\n\nFor the expression `a= b= 3`, if we do the above, we end up with the tree:\n   \n```\n      =\n     / \\\n    =   3\n   / \\\n  a   b\n```\n\nWe don't want to do `a= b` before then trying to assign the 3 to this\nleft sub-tree. Instead, what we want to generate is this tree:\n\n```\n        =\n       / \\\n      =   a\n     / \\\n    3   b\n```\n\nI've reversed the leaf nodes to be in assembly output order. We first\nstore 3 in `b`. Then the result of this assignment, 3, is stored in `a`.\n\n### Modifying the Pratt Parser\n\nWe are using a Pratt parser to correctly parse the precedences of our\nbinary operators. I did a search to find out how to add right-associativity\nto a Pratt parser, and found this information in\n[Wikipedia](https://en.wikipedia.org/wiki/Operator-precedence_parser):\n\n```\n   while lookahead is a binary operator whose precedence is greater than op's,\n   or a right-associative operator whose precedence is equal to op's\n```\n\nSo, for right-associative operators, we test if the next operator\nhas the same precedence as the operator we are up to. That's a simple\nmodification to the parser's logic. I've introduced a new function\nin `expr.c` to determine if an operator is right-associative:\n\n```c\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return(1);\n  return(0);\n}\n\n```\n\nIn `binexpr()` we alter the while loop as mentioned before, and we\nalso put in A_ASSIGN-specific code to swap the child trees around:\n\n```c\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  left = prefix();\n  ...\n\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n         (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    ...\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    ASTop = binastop(tokentype);\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue= 1;\n      ...\n\n      // Switch left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp= left; left= right; right= ltemp;\n    } else {\n      // We are not doing an assignment, so both trees should be rvalues\n      left->rvalue= 1;\n      right->rvalue= 1;\n    }\n    ...\n  }\n  ...\n}\n```\n\nNotice also the code to explicitly mark the right-hand side of the\nassignment expression as an rvalue. And, for non assignments, both\nsides of the expression get marked as rvalues.\n\nScattered through `binexpr()` are a few more lines of code to\nexplicitly set a tree to be an rvalue. These get performed when\nwe hit a leaf node. For example the `a` identifier in `b= a;` needs\nto be marked as an rvalue, but we will never enter the body of the\nwhile loop to do this.\n\n## Printing Out the Tree\n\nThat is the parser changes out of the road. We now have several nodes\nmarked as rvalues, and some not marked at all. At this point, I realised\nthat I was having trouble visualising the AST trees that get generated.\nI've written a function called `dumpAST()` in `tree.c` to print out\neach AST tree to standard output. It's not sophisticated. The compiler\nnow has a `-T` command line argument which sets an internal flag,\n`O_dumpAST`. And the `global_declarations()` code in `decl.c` now does:\n\n```c\n       // Parse a function declaration and\n       // generate the assembly code for it\n       tree = function_declaration(type);\n       if (O_dumpAST) {\n         dumpAST(tree, NOLABEL, 0);\n         fprintf(stdout, \"\\n\\n\");\n       }\n       genAST(tree, NOLABEL, 0);\n\n```\n\nThe tree dumper code prints out each node in the order tree traversal\norder, so the output isn't tree shaped. However, the indentation of\neach node indicates its depth in the tree.\n\nLet's take a look at some example AST trees for assignment expressions.\nWe'll start with `a= b= 34;`:\n\n```\n      A_INTLIT 34\n    A_WIDEN\n    A_IDENT b\n  A_ASSIGN\n  A_IDENT a\nA_ASSIGN\n```\n\nThe 34 is small enough to be a char-sized literal, but it gets widened\nto match the type of `b`. `A_IDENT b` doesn't say \"rvalue\", so it's a\nlvalue. The value of 34 is stored in the `b` lvalue. This value is then\nstored in the `a` lvalue.\n\nNow let's try `a= b + 34;`:\n\n```\n    A_IDENT rval b\n      A_INTLIT 34\n    A_WIDEN\n  A_ADD\n  A_IDENT a\nA_ASSIGN\n```\n\nYou can see the \"rval `b`\" now, so `b`'s value is loaded into a register,\nwhereas the result of the `b+34` expression is stored in the `a` lvalue.\n\nLet's do one more, `*x= *y`:\n\n```\n    A_IDENT y\n  A_DEREF rval\n    A_IDENT x\n  A_DEREF\nA_ASSIGN\n```\n\nThe identifier `y` is dereferenced and this rvalue is loaded. This is then\nstored in the lvalue which is `x` dereferenced.\n\n## Converting The Above into Code\n\nNow that the lvalue and rvalues nodes are clearly identified, we can turn\nour attention to how we translate each into assembly code. There are many\nnodes like integer literals, addition etc. which are clearly rvalues. It\nis only the AST node types which could possibly be lvalues that the code\nin `genAST()` in `gen.c` needs to worry about. Here is what I have for these\nnode types:\n\n```c\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop== A_DEREF)\n        return (cgloadglob(n->v.id));\n      else\n        return (NOREG);\n\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n        case A_IDENT: return (cgstorglob(leftreg, n->right->v.id));\n        case A_DEREF: return (cgstorderef(leftreg, rightreg, n->right->type));\n        default: fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n        return (cgderef(leftreg, n->left->type));\n      else\n        return (leftreg);\n```\n\n### Changes to the x86-64 Code Generator\n\nThe only change to `cg.c` is a function which allows us to store a value through\na pointer:\n\n```c\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n```\n\nwhich is nearly exactly the opposite of `cgderef()` which appears immediately\nbefore this new function.\n\n## Conclusion and What's Next\n\nFor this part of the journey, I think I took two or three different design\ndirections, tried them, hit a dead end and backed out before I reached the\nsolution described here. I know that, in SubC, Nils passes a single \"lvalue\"\nstructure which holds the \"lvalue\"-ness of the node of the AST tree being \nprocessed at any point in time. But his tree only holds one expression; the\nAST tree for this compiler holds one whole function's worth of nodes. And I'm\nsure that, if you looked in three other compilers, you would probably find\nthree other solutions too.\n\nThere are many things that we could take on next. There are a bunch of C operators\nthat would be relatively easy to add to the compiler. We have A_SCALE, so we\ncould attempt structures. As yet, there are no local variables, which will need\nattending to at some point. And, we should generalise functions to have multiple\narguments and the ability to access them.\n\nIn the next part of our compiler writing journey,\nI'd like to tackle arrays. This will be a combination of dereferencing,\nlvalues and rvalues, and scaling the array indices by the size of the\narray's elements. We have all the semantic components in place, but we'll\nneed to add tokens, parsing and the actual index functionality. It should\nbe an interesting topic like this one was. [Next step](../19_Arrays_pt1/Readme.md)\n"
  },
  {
    "path": "18_Lvalues_Revisited/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\nstatic char *dreglist[4] = { \"%r8d\", \"%r9d\", \"%r10d\", \"%r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovzbl\\t%s(\\%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(\\%%rip)\\n\", breglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(\\%%rip)\\n\", dreglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Gsym[id].name);\n  switch(typesize) {\n    case 1: fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Gsym[id].name); break;\n    case 4: fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Gsym[id].name); break;\n    case 8: fprintf(Outfile, \"%s:\\t.quad\\t0\\n\", Gsym[id].name); break;\n    default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Gsym[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\tprintint\\n\");\n  fprintf(Outfile, \"\\tnop\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4, 4, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Gsym[id].name);\n  switch(typesize) {\n    case 1: fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Gsym[id].name); break;\n    case 4: fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Gsym[id].name); break;\n    default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\nstatic char *dreglist[4] = { \"r8d\", \"r9d\", \"r10d\", \"r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\tsection\\t.text\\n\"\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r], reglist[r]);\n      fprintf(Outfile, \"\\tmov\\t%s, dword [%s]\\n\", dreglist[r], \n              Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call printint() with the given register\nvoid cgprintint(int r) {\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\tprintint\\n\");\n  free_register(r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", Gsym[id].name);\n  switch(typesize) {\n    case 1: fprintf(Outfile, \"%s:\\tdb\\t0\\n\", Gsym[id].name); break;\n    case 4: fprintf(Outfile, \"%s:\\tdd\\t0\\n\", Gsym[id].name); break;\n    case 8: fprintf(Outfile, \"%s:\\tdq\\t0\\n\", Gsym[id].name); break;\n    default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Gsym[id].name);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, word [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n\nextern_ int O_dumpAST;\n"
  },
  {
    "path": "18_Lvalues_Revisited/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      break;\n    case T_INT:\n      type = P_INT;\n      break;\n    case T_LONG:\n      type = P_LONG;\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'  ;\n//\n// Parse the declaration of a variable.\n// The identifier has been scanned & we have the type\nvoid var_declaration(int type) {\n  int id;\n\n  // Text now has the identifier's name.\n  // Add it as a known identifier\n  // and generate its space in assembly\n  id = addglob(Text, type, S_VARIABLE, 0);\n  genglobsym(id);\n  // Get the trailing semicolon\n  semi();\n}\n\n//\n// function_declaration: type identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function.\n// The identifier has been scanned & we have the type\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int nameslot, endlabel;\n\n  // Text now has the identifier's name.\n  // Get a label-id for the end label, add the function\n  // to the symbol table, and set the Functionid global\n  // to the function's symbol-id\n  endlabel = genlabel();\n  nameslot = addglob(Text, type, S_FUNCTION, endlabel);\n  Functionid = nameslot;\n\n  // Scan in the parentheses\n  lparen();\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, nameslot));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n       // Parse the function declaration and\n       // generate the assembly code for it\n       tree = function_declaration(type);\n       if (O_dumpAST) { dumpAST(tree, NOLABEL, 0); fprintf(stdout, \"\\n\\n\"); }\n       genAST(tree, NOLABEL, 0);\n    } else {\n\n       // Parse the global variable declaration\n       var_declaration(type);\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genprintint(int reg);\nvoid genglobsym(int id);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nvoid cgprintint(int r);\nint cgcall(int r, int id);\nint cgstorglob(int r, int id);\nvoid cgglobsym(int id);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\n\n// expr.c\nstruct ASTnode *funccall(void);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name, int type, int stype, int endlabel);\n\n// decl.c\nvoid var_declaration(int type);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint parse_type(void);\nint pointer_to(int type);\nint value_at(int type);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "18_Lvalues_Revisited/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  // Operators\n  T_ASSIGN,\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n  // Structural tokens\n  T_INTLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_AMPER, T_LOGAND,\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN= 1, A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n#define NOLABEL\t 0\t\t// Use NOLABEL when we have no label to\n\t\t\t\t// pass to genAST()\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n};\n"
  },
  {
    "path": "18_Lvalues_Revisited/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a function call with a single expression\n// argument and return its AST\nstruct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined,\n  // then make a leaf node for it. XXX Add structural type test\n  if ((id = findglob(Text)) == -1) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Gsym[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n\tn = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n      break;\n\n    case T_IDENT:\n      // This could be a variable or a function call.\n      // Scan in the next token to find out\n      scan(&Token);\n\n      // It's a '(', so a function call\n      if (Token.token == T_LPAREN)\n\treturn (funccall());\n\n      // Not a function call, so reject the new token\n      reject_token(&Token);\n\n      // Check that the variable exists. XXX Add structural type test\n      id = findglob(Text);\n      if (id == -1)\n\tfatals(\"Unknown variable\", Text);\n\n      // Make a leaf AST node for it\n      n = mkastleaf(A_IDENT, Gsym[id].type, id);\n      break;\n\n    default:\n      fatald(\"Syntax error, token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return(1);\n  return(0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n   0, 10,\t\t\t// T_EOF,  T_ASSIGN\n  20, 20,\t\t\t// T_PLUS, T_MINUS\n  30, 30,\t\t\t// T_STAR, T_SLASH\n  40, 40,\t\t\t// T_EQ, T_NE\n  50, 50, 50, 50\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*' prefix_expression\n//     | '&' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n    case T_AMPER:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Ensure that it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"& operator must be followed by an identifier\");\n\n      // Now change the operator to A_ADDR and the type to\n      // a pointer to the original type\n      tree->op = A_ADDR;\n      tree->type = pointer_to(tree->type);\n      break;\n    case T_STAR:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's either another deref or an\n      // identifier\n      if (tree->op != A_IDENT && tree->op != A_DEREF)\n\tfatal(\"* operator must be followed by an identifier or *\");\n\n      // Prepend an A_DEREF operation to the tree\n      tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n      break;\n    default:\n      tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN) {\n      left->rvalue= 1; return(left);\n  }\n\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n         (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue= 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (left == NULL)\n        fatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp= left; left= right; right= ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue= 1;\n      right->rvalue= 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n        fatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n        left = ltemp;\n      if (rtemp != NULL)\n        right = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(binastop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon or ')', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN) {\n      left->rvalue= 1; return(left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue= 1; return(left);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOLABEL, n->op);\n      genfreeregs();\n      genAST(n->right, NOLABEL, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->v.id);\n      genAST(n->left, NOLABEL, n->op);\n      cgfuncpostamble(n->v.id);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue, n->type));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop== A_DEREF)\n        return (cgloadglob(n->v.id));\n      else\n        return (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n        case A_IDENT: return (cgstorglob(leftreg, n->right->v.id));\n\tcase A_DEREF: return (cgstorderef(leftreg, rightreg, n->right->type));\n        default: fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_FUNCCALL:\n      return (cgcall(leftreg, n->v.id));\n    case A_ADDR:\n      return (cgaddress(n->v.id));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n        return (cgderef(leftreg, n->left->type));\n      else\n        return (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->v.size) {\n\tcase 2: return(cgshlconst(leftreg, 1));\n\tcase 4: return(cgshlconst(leftreg, 2));\n\tcase 8: return(cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n          rightreg= cgloadint(n->v.size, P_INT);\n          return (cgmul(leftreg, rightreg));\n      }\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genprintint(int reg) {\n  cgprintint(reg);\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n  Globs = 0;\n  O_dumpAST = 0;\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-T] infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nint main(int argc, char *argv[]) {\n  int i;\n\n  // Initialise the globals\n  init();\n\n  // Scan for command-line options\n  for (i=1; i<argc; i++) {\n    if (*argv[i] != '-') break;\n    for (int j=1; argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'T': O_dumpAST =1; break;\n\tdefault: usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have an input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Open up the input file\n  if ((Infile = fopen(argv[i], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[i], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n  // For now, ensure that void printint() is defined\n  addglob(\"printint\", P_CHAR, S_FUNCTION, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  return (0);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tfatalc(\"Unrecognised character\", c);\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Gsym[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Gsym[Functionid].type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration.\n      // XXX: These are globals at present.\n      type = parse_type();\n      ident();\n      var_declaration(type);\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table.\n// Also set up its type and structural type.\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int endlabel) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  Gsym[y].type = type;\n  Gsym[y].stype = stype;\n  Gsym[y].endlabel = endlabel;\n  return (y);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input01.c",
    "content": "void main()\n{ printint(12 * 3);\n  printint(18 - 2 * 4);\n  printint(1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input02.c",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printint(fred + jim);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input03.c",
    "content": "void main()\n{\n  int x;\n  x= 1;     printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input04.c",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  printint(x);\n  x= 7 <= 9; printint(x);\n  x= 7 != 9; printint(x);\n  x= 7 == 7; printint(x);\n  x= 7 >= 7; printint(x);\n  x= 7 <= 7; printint(x);\n  x= 9 > 7;  printint(x);\n  x= 9 >= 7; printint(x);\n  x= 9 != 7; printint(x);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input05.c",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printint(i);\n  } else {\n    printint(j);\n  }\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input06.c",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printint(i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input07.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input08.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input09.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printint(2 * b - a); }\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input10.c",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; printint(j);\n  i= 10; printint(i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 2; j= j + 1) { printint(j); }\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input11.c",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; printint(i);\n  j= 20; printint(j);\n  k= 30; printint(k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 4; j= j + 1) { printint(j); }\n  for (k= 1;   k <= 5; k= k + 1) { printint(k); }\n  return(i);\n  printint(12345);\n  return(3);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input12.c",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printint(x);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input13.c",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input14.c",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input15.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printint(a);\n  b= &a; c= *b; printint(c);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input16.c",
    "content": "int   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printint(c);\n  e= &c + 1; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input17.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printint(a);\n  e= &d; *e= 12; printint(d);\n  return(0);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input18.c",
    "content": "int main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printint(a);\n  printint(b);\n  return(0);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/input18a.c",
    "content": "int   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printint(a);\n  d= &c; *d= 16; printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" ]\n   then\n     cc -o out $i ../lib/printint.c\n     ./out > out.$i\n     rm -f out\n   fi\ndone\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "18_Lvalues_Revisited/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -Wall -o out out.o ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "18_Lvalues_Revisited/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i=0; i < level; i++) fprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) { Lend = gendumplabel();\n        fprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level+2);\n      dumpAST(n->mid, NOLABEL, level+2);\n      if (n->right) dumpAST(n->right, NOLABEL, level+2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i=0; i < level; i++) fprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level+2);\n      dumpAST(n->right, NOLABEL, level+2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op==A_GLUE) level= -2;\n\n  // General AST node handling\n  if (n->left) dumpAST(n->left, NOLABEL, level+2);\n  if (n->right) dumpAST(n->right, NOLABEL, level+2);\n\n\n  for (int i=0; i < level; i++) fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\"); return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", Gsym[n->v.id].name); return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\"); return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\"); return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\"); return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\"); return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\"); return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\"); return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\"); return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\"); return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\"); return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\"); return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->v.intvalue); return;\n    case A_IDENT:\n      if (n->rvalue)\n        fprintf(stdout, \"A_IDENT rval %s\\n\", Gsym[n->v.id].name);\n      else\n        fprintf(stdout, \"A_IDENT %s\\n\", Gsym[n->v.id].name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\"); return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\"); return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\"); return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", Gsym[n->v.id].name); return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", Gsym[n->v.id].name); return;\n    case A_DEREF:\n      if (n->rvalue)\n        fprintf(stdout, \"A_DEREF rval\\n\");\n      else\n        fprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->v.size); return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "18_Lvalues_Revisited/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  if (type == P_CHAR || type == P_INT || type == P_LONG)\n    return (1);\n  return (0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  if (type == P_VOIDPTR || type == P_CHARPTR ||\n      type == P_INTPTR || type == P_LONGPTR)\n    return (1);\n  return (0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOID:\n      newtype = P_VOIDPTR;\n      break;\n    case P_CHAR:\n      newtype = P_CHARPTR;\n      break;\n    case P_INT:\n      newtype = P_INTPTR;\n      break;\n    case P_LONG:\n      newtype = P_LONGPTR;\n      break;\n    default:\n      fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOIDPTR:\n      newtype = P_VOID;\n      break;\n    case P_CHARPTR:\n      newtype = P_CHAR;\n      break;\n    case P_INTPTR:\n      newtype = P_INT;\n      break;\n    case P_LONGPTR:\n      newtype = P_LONG;\n      break;\n    default:\n      fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1) \n\treturn (mkastunary(A_SCALE, rtype, tree, rsize));\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g -Wall $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g -Wall $(SRCN)\n\ncomp1arm: $(ARMSRCS)\n\tcc -o comp1arm -g -Wall $(ARMSRCS)\n\tcp comp1arm comp1\n\nclean:\n\trm -f comp1 comp1arm compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: comp1arm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\ntest20: comp1 tests/input20.c lib/printint.c\n\t./comp1 tests/input20.c\n\tcc -o out out.s lib/printint.c\n\t./out\n\narmtest20: comp1arm tests/input20.c lib/printint.c\n\t./comp1 tests/input20.c\n\tcc -o out out.s lib/printint.c\n\t./out\n\ntest20n: compn tests/input20.c lib/printint.c\n\t./compn tests/input20.c\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out lib/printint.c out.o\n\t./out\n"
  },
  {
    "path": "19_Arrays_pt1/Notes",
    "content": "  int ary[5];\n  int *ptr;\n\n  ary[3]= 63;\t\t    // Set ary[3] (lvalue) to 63\n  ptr   = ary;\t\t    // Point ptr to base of ary\n  // ary= ptr;\t\t    // error: assignment to expression with array type\n  ptr   = &ary[0];\t    // Also point ptr to base of ary, ary[0] is lvalue\n  ptr[4]= 72;\t\t    // Use ptr like an array, ptr[4] is an lvalue\n\n        .globl  z\nz:     .quad   1\n        .quad   2\n        .quad   3\n        .quad   4\n        .globl  zc\nzc:    .byte   1\n        .byte   2\n        .byte   3\n        .byte   4\n        .byte   0\n        .byte   0\n        .byte   0\n        .byte   0\n"
  },
  {
    "path": "19_Arrays_pt1/Readme.md",
    "content": "# Part 19: Arrays, part 1\n\n> *My lecturer for the first year of university was a Scotsman with a\n  very heavy accent. Around the third or fourth week of first term,\n  he began saying \"Hurray!\" a lot in class. It took me about twenty\n  minutes to work out he was saying \"array\".*\n\nSo, we begin the work to add arrays to the compiler in this part of\nthe journey. I sat down and wrote a small C program to see what\nsort of functionality I should try to implement:\n\n```c\n  int ary[5];               // Array of five int elements\n  int *ptr;                 // Pointer to an int\n\n  ary[3]= 63;               // Set ary[3] (lvalue) to 63\n  ptr   = ary;              // Point ptr to base of ary\n  // ary= ptr;              // error: assignment to expression with array type\n  ptr   = &ary[0];          // Also point ptr to base of ary, ary[0] is lvalue\n  ptr[4]= 72;               // Use ptr like an array, ptr[4] is an lvalue\n```\n\nArrays are *like* pointers in that we can dereference both a pointer\nand an array with the \"[ ]\" syntax to get access to a specific element.\nWe can use the array's name as a \"pointer\" and save the array's base\ninto a pointer. We can get the address of an element in the array.\nBut one thing we can't do is \"overwrite\" the base of an array\nwith a pointer: the elements of the array are mutable, but the base\naddress of the array is not mutable.\n\nIn this part of the journey, I'll add in:\n\n + declarations of array with a fixed size but no initialisation list\n + array indexes as rvalues in an expression\n + array indexes as an lvalue in an assignment\n\nI also won't implement more than one dimension in each array.\n\n## Parentheses in Expressions\n\nAt some point I want to try this out:  `*(ptr + 2)` which should\nend up being the same as `ptr[2]`. But we haven't allowed parentheses\nin expressions yet, so now it's time to add them.\n\n### C Grammar in BNF\n\nOn the web there is a page with the\n[BNF Grammar for C](https://www.lysator.liu.se/c/ANSI-C-grammar-y.html)\nwritten by Jeff Lee in 1985. I like to reference it to give me ideas\nand to confirm that I'm not making too many mistakes.\n\nOne thing to note is that, instead of implemnting the priority of\nthe binary expression operators in C, the grammar uses recursive\ndefinitions to make the priorities explicit. Thus:\n\n```\nadditive_expression\n        : multiplicative_expression\n        | additive_expression '+' multiplicative_expression\n        | additive_expression '-' multiplicative_expression\n        ;\n```\n\nshows that we descend into \"multiplicative_expression\" while we\nare parsing an \"additive_expression\", thus giving the '*' and '/'\noperators a higher precedence than the '+' and '-' operators.\n\nRight at the top of the expression precedence hierarchy is:\n\n```\nprimary_expression\n        : IDENTIFIER\n        | CONSTANT\n        | STRING_LITERAL\n        | '(' expression ')'\n        ;\n```\n\nWe already have a `primary()` function which is called to find\nT_INTLIT and T_IDENT tokens, and this conforms to Jeff Lee's C grammar.\nIt's thus the perfect place to add the parsing of parentheses in\nexpressions.\n\nWe already have T_LPAREN and T_RPAREN as tokens in our language, so\nthere is no work to be done in the lexical scanner.\n\nInstead, we simply modify `primary()` to do the extra parsing:\n\n```c\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  ...\n\n  switch (Token.token) {\n  case T_INTLIT:\n  ...\n  case T_IDENT:\n  ...\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n    default:\n    fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n```\n\nAnd that's it! Just a few extra lines to add parentheses in expression.\nYou'll notice that I explicitly call `rparen()` in the new code and\nreturn instead of breaking out of the switch statement. If the code\nhad left the switch statement, the `scan(&Token);` before the final\nreturn would not strictly enforce the requirement for a ')' token\nto match the opening '(' token.\n\nThe `test/input19.c` test checks that parentheses are working:\n\n```c\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printint(e);\n```\n\nand it should print out 30, i.e. `6 * 5`.\n\n## Symbol Table Changes\n\nWe have scalar variables (with only one value) and functions in our\nsymbol table. It's time to add arrays. Later on, we'll want to\nget the number of elements in each array with the `sizeof()` operator.\nHere are the changes in `defs.h`:\n\n```c\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  int stype;                    // Structural type for the symbol\n  int endlabel;                 // For S_FUNCTIONs, the end label\n  int size;                     // Number of elements in the symbol\n};\n```\n\nFor now, we will treat arrays as pointers, and so the type for an\narray is \"pointer to\" something, e.g. \"pointer to int\" if the elements\nin the array are `int`s. We also need to add one more argument to\n`addglob()` in `sym.c`:\n\n```c\nint addglob(char *name, int type, int stype, int endlabel, int size) {\n  ...\n}\n```\n\n## Parsing Array Declarations\n\nFor now, I'm only going to allow declarations of arrays with a size.\nThe BNF grammar for variable declarations is now:\n\n```\n variable_declaration: type identifier ';'\n        | type identifier '[' P_INTLIT ']' ';'\n        ;\n```\n\nSo we need to see what token is next in `var_declaration()` in `decl.c`\nand process either a scalar variable declaration or an array declaration:\n\n```c\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type\nvoid var_declaration(int type) {\n  int id;\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      id = addglob(Text, pointer_to(type), S_ARRAY, 0, Token.intvalue);\n      genglobsym(id);\n    }\n\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    ...      // Previous code\n  }\n  \n    // Get the trailing semicolon\n  semi();\n}\n```\n\nI think that's pretty straight-forward code Later on, we'll add\ninitialisation lists to the declaration of arrays.\n\n## Generating the Array Storage\n\nNow that we know the size of the array, we can modify `cgglobsym()` to\nallocate this space in the assembler:\n\n```c\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  // Generate the global identity and the label\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"%s:\", Gsym[id].name);\n\n  // Generate the space\n  for (int i=0; i < Gsym[id].size; i++) {\n    switch(typesize) {\n      case 1: fprintf(Outfile, \"\\t.byte\\t0\\n\"); break;\n      case 4: fprintf(Outfile, \"\\t.long\\t0\\n\"); break;\n      case 8: fprintf(Outfile, \"\\t.quad\\t0\\n\"); break;\n      default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n}\n```\n\nWith this in place, we can now declare arrays such as:\n\n```c\n  char a[10];\n  int  b[25];\n  long c[100];\n```\n\n## Parsing Array Indexes\n\nIn this part I don't want to get too adventurous. I only want to\nget basic array indexes as rvalues and lvalues to work. The\n`test/input20.c` program has the functionality that I want to achieve:\n\n```c\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12; a= b[3];\n  printint(a); return(0);\n}\n```\n\nBack in the BNF grammar for C, we can see that array indexes have\n*slightly* lower priority than parentheses:\n\n```\nprimary_expression\n        : IDENTIFIER\n        | CONSTANT\n        | STRING_LITERAL\n        | '(' expression ')'\n        ;\n\npostfix_expression\n        : primary_expression\n        | postfix_expression '[' expression ']'\n          ...\n```\n\nBut for now, I'll parse array indexes also in the `primary()` function.\nThe code to do the semantic analysis ended up being big enough to warrant\na new function:\n\n\n```c\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n\n  switch (Token.token) {\n  case T_IDENT:\n    // This could be a variable, array index or a\n    // function call. Scan in the next token to find out\n    scan(&Token);\n\n    // It's a '(', so a function call\n    if (Token.token == T_LPAREN) return (funccall());\n\n    // It's a '[', so an array reference\n    if (Token.token == T_LBRACKET) return (array_access());\n```\n\nAnd here is the `array_access()` function:\n\n```c\n// Parse the index into an array and\n// return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  int id;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((id = findglob(Text)) == -1 || Gsym[id].stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, Gsym[id].type, id);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, Gsym[id].type, left, NULL, right, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, 0);\n  return (left);\n}\n```\n\nFor the array `int x[20];` and the array index `x[6]`, we need to\nscale the index (6) by the size of `int`s (4), and add this to the\naddress of the array base. Then this element has to be dereferenced.\nWe leave it marked as an lvalue, because we could be trying to do:\n\n```c\n  x[6] = 100;\n```\n\nIf it does become an rvalue, then `binexpr()` will set the `rvalue`\nflag in the A_DEREF AST node.\n\n### The Generated AST Trees\n\nGoing back to our test program `tests/input20.c`, the code that will\nproduce AST trees with array indexes are:\n\n```c\n  b[3]= 12; a= b[3];\n```\n\nRunning `comp1 -T tests/input20.c`, we get:\n\n```\n    A_INTLIT 12\n  A_WIDEN\n      A_ADDR b\n        A_INTLIT 3    # 3 is scaled by 4\n      A_SCALE 4\n    A_ADD             # and then added to b's address\n  A_DEREF             # and derefenced. Note, stll an lvalue\nA_ASSIGN\n\n      A_ADDR b\n        A_INTLIT 3    # As above\n      A_SCALE 4\n    A_ADD\n  A_DEREF rval        # but the dereferenced address will be an rvalue\n  A_IDENT a\nA_ASSIGN\n```\n\n### Other Minor Parse Changes\n\nThere are a couple of minor changes to the parser in `expr.c` which took\nme a while to debug. I needed to be more stringent with the input to\nthe operator precedence lookup function:\n\n```c\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype >= T_VOID)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  ...\n}\n```\n\nUntil I got the parsing right, I was sending a token not in the\nprecedence table, and `op_precedence()` was reading past the end of the\ntable. Oops! Don't you just love C?!\n\nThe other change is that, now that we can use expressions as array\nindexes (e.g. `x[ a+2 ]`), we have to expect the ']' token can end\nan expression. So, at the end of `binexpr()`:\n\n```c\n    // Update the details of the current token.\n    // If we hit a semicolon, ')' or ']', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN\n        || tokentype == T_RBRACKET) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n```\n\n## Changes to the Code Generator\n\nThere are none. We had all the necessary components in our compiler\nalready: scaling integer values, obtaining the address of a variable etc.\nFor our test code:\n\n```c\n  b[3]= 12; a= b[3];\n```\n\nwe generate the x86-64 assembly code:\n\n```\n        movq    $12, %r8\n        leaq    b(%rip), %r9    # Get b's address\n        movq    $3, %r10\n        salq    $2, %r10        # Shift 3 by 2, i.e. 3 * 4\n        addq    %r9, %r10       # Add to b's address\n        movq    %r8, (%r10)     # Save 12 into b[3]\n\n        leaq    b(%rip), %r8    # Get b's address\n        movq    $3, %r9\n        salq    $2, %r9         # Shift 3 by 2, i.e. 3 * 4\n        addq    %r8, %r9        # Add to b's address\n        movq    (%r9), %r9      # Load b[3] into %r9\n        movl    %r9d, a(%rip)   # and store in a\n```\n\n## Conclusion and What's Next\n\nThe parsing changes to add basic array declarations and array\nexpressions (in terms of dealing with the syntax) were quite easy to\ndo. What I found difficult was getting the AST tree nodes correct to\nscale, add to the base address, and set as lvalue/rvalue. Once this\nwas right, the existing code generator produces the right assembly output.\n\nIn the next part of our compiler writing journey, we'll add character\nand string literals to our language and find a way to print them out. [Next step](../20_Char_Str_Literals/Readme.md)\n"
  },
  {
    "path": "19_Arrays_pt1/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\nstatic char *dreglist[4] = { \"%r8d\", \"%r9d\", \"%r10d\", \"%r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovzbl\\t%s(\\%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(\\%%rip)\\n\", breglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(\\%%rip)\\n\", dreglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  // Generate the global identity and the label\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"%s:\", Gsym[id].name);\n\n  // Generate the space\n  for (int i=0; i < Gsym[id].size; i++) {\n    switch(typesize) {\n      case 1: fprintf(Outfile, \"\\t.byte\\t0\\n\"); break;\n      case 4: fprintf(Outfile, \"\\t.long\\t0\\n\"); break;\n      case 8: fprintf(Outfile, \"\\t.quad\\t0\\n\"); break;\n      default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Gsym[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4, 4, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Gsym[id].name);\n  switch(typesize) {\n    case 1: fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Gsym[id].name); break;\n    case 4: fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Gsym[id].name); break;\n    default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\nstatic char *dreglist[4] = { \"r8d\", \"r9d\", \"r10d\", \"r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\tsection\\t.text\\n\"\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r], reglist[r]);\n      fprintf(Outfile, \"\\tmov\\t%s, dword [%s]\\n\", dreglist[r], \n              Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  // Generate the global identity and the label\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"%s:\", Gsym[id].name);\n\n  // Generate the space\n  // original version\n  for (int i=0; i < Gsym[id].size; i++) {\n    switch(typesize) {\n      case 1: fprintf(Outfile, \"\\tdb\\t0\\n\"); break;\n      case 4: fprintf(Outfile, \"\\tdd\\t0\\n\"); break;\n      case 8: fprintf(Outfile, \"\\tdq\\t0\\n\"); break;\n      default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(typesize) {\n    case 1: fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", Gsym[id].size); break;\n    case 4: fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", Gsym[id].size); break;\n    case 8: fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", Gsym[id].size); break;\n    default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Gsym[id].name);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, word [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n\nextern_ int O_dumpAST;\n"
  },
  {
    "path": "19_Arrays_pt1/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      break;\n    case T_INT:\n      type = P_INT;\n      break;\n    case T_LONG:\n      type = P_LONG;\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type\nvoid var_declaration(int type) {\n  int id;\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      id = addglob(Text, pointer_to(type), S_ARRAY, 0, Token.intvalue);\n      genglobsym(id);\n    }\n\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    id = addglob(Text, type, S_VARIABLE, 0, 1);\n    genglobsym(id);\n  }\n\n  // Get the trailing semicolon\n  semi();\n}\n\n//\n// function_declaration: type identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function.\n// The identifier has been scanned & we have the type\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int nameslot, endlabel;\n\n  // Text now has the identifier's name.\n  // Get a label-id for the end label, add the function\n  // to the symbol table, and set the Functionid global\n  // to the function's symbol-id\n  endlabel = genlabel();\n  nameslot = addglob(Text, type, S_FUNCTION, endlabel, 0);\n  Functionid = nameslot;\n\n  // Scan in the parentheses\n  lparen();\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, nameslot));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n       // Parse the function declaration and\n       // generate the assembly code for it\n       tree = function_declaration(type);\n       if (O_dumpAST) { dumpAST(tree, NOLABEL, 0); fprintf(stdout, \"\\n\\n\"); }\n       genAST(tree, NOLABEL, 0);\n    } else {\n\n       // Parse the global variable declaration\n       var_declaration(type);\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "19_Arrays_pt1/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(int id);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(int r, int id);\nint cgstorglob(int r, int id);\nvoid cgglobsym(int id);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name, int type, int stype, int endlabel, int size);\n\n// decl.c\nvoid var_declaration(int type);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint parse_type(void);\nint pointer_to(int type);\nint value_at(int type);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "19_Arrays_pt1/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  // Operators\n  T_ASSIGN,\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n  // Structural tokens\n  T_INTLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET,\n  T_AMPER, T_LOGAND,\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN= 1, A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n#define NOLABEL\t 0\t\t// Use NOLABEL when we have no label to\n\t\t\t\t// pass to genAST()\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n  int size;\t\t\t// Number of elements in the symbol\n};\n"
  },
  {
    "path": "19_Arrays_pt1/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a function call with a single expression\n// argument and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((id = findglob(Text)) == -1 || Gsym[id].stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Gsym[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and\n// return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  int id;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((id = findglob(Text)) == -1 || Gsym[id].stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, Gsym[id].type, id);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, Gsym[id].type, left, NULL, right, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, 0);\n  return (left);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n    break;\n\n  case T_IDENT:\n    // This could be a variable, array index or a\n    // function call. Scan in the next token to find out\n    scan(&Token);\n\n\n    // It's a '(', so a function call\n    if (Token.token == T_LPAREN)\n      return (funccall());\n\n    // It's a '[', so an array reference\n    if (Token.token == T_LBRACKET) {\n      return (array_access());\n    }\n    // Not a function call, so reject the new token\n    reject_token(&Token);\n\n    // Check that the variable exists.\n    id = findglob(Text);\n    if (id == -1 || Gsym[id].stype != S_VARIABLE)\n      fatals(\"Unknown variable\", Text);\n\n    // Make a leaf AST node for it\n    n = mkastleaf(A_IDENT, Gsym[id].type, id);\n    break;\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10,\t\t\t// T_EOF,  T_ASSIGN\n  20, 20,\t\t\t// T_PLUS, T_MINUS\n  30, 30,\t\t\t// T_STAR, T_SLASH\n  40, 40,\t\t\t// T_EQ, T_NE\n  50, 50, 50, 50\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype >= T_VOID)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*' prefix_expression\n//     | '&' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN || tokentype == T_RBRACKET) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (left == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(binastop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon, ')' or ']', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN\n\t|| tokentype == T_RBRACKET) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOLABEL, n->op);\n      genfreeregs();\n      genAST(n->right, NOLABEL, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->v.id);\n      genAST(n->left, NOLABEL, n->op);\n      cgfuncpostamble(n->v.id);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue, n->type));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop== A_DEREF)\n        return (cgloadglob(n->v.id));\n      else\n        return (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n        case A_IDENT: return (cgstorglob(leftreg, n->right->v.id));\n\tcase A_DEREF: return (cgstorderef(leftreg, rightreg, n->right->type));\n        default: fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_FUNCCALL:\n      return (cgcall(leftreg, n->v.id));\n    case A_ADDR:\n      return (cgaddress(n->v.id));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n        return (cgderef(leftreg, n->left->type));\n      else\n        return (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->v.size) {\n\tcase 2: return(cgshlconst(leftreg, 1));\n\tcase 4: return(cgshlconst(leftreg, 2));\n\tcase 8: return(cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n          rightreg= cgloadint(n->v.size, P_INT);\n          return (cgmul(leftreg, rightreg));\n      }\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "19_Arrays_pt1/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n  Globs = 0;\n  O_dumpAST = 0;\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-T] infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nint main(int argc, char *argv[]) {\n  int i;\n\n  // Initialise the globals\n  init();\n\n  // Scan for command-line options\n  for (i=1; i<argc; i++) {\n    if (*argv[i] != '-') break;\n    for (int j=1; argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'T': O_dumpAST =1; break;\n\tdefault: usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have an input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Open up the input file\n  if ((Infile = fopen(argv[i], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[i], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n  // For now, ensure that void printint() is defined\n  addglob(\"printint\", P_CHAR, S_FUNCTION, 0, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  return (0);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tfatalc(\"Unrecognised character\", c);\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    default:\n\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Gsym[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Gsym[Functionid].type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration.\n      // XXX: These are globals at present.\n      type = parse_type();\n      ident();\n      var_declaration(type);\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "19_Arrays_pt1/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + endlabel: if this is a function\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int endlabel, int size) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  Gsym[y].type = type;\n  Gsym[y].stype = stype;\n  Gsym[y].endlabel = endlabel;\n  Gsym[y].size = size;\n  return (y);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input01.c",
    "content": "void main()\n{ printint(12 * 3);\n  printint(18 - 2 * 4);\n  printint(1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input02.c",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printint(fred + jim);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input03.c",
    "content": "void main()\n{\n  int x;\n  x= 1;     printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input04.c",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  printint(x);\n  x= 7 <= 9; printint(x);\n  x= 7 != 9; printint(x);\n  x= 7 == 7; printint(x);\n  x= 7 >= 7; printint(x);\n  x= 7 <= 7; printint(x);\n  x= 9 > 7;  printint(x);\n  x= 9 >= 7; printint(x);\n  x= 9 != 7; printint(x);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input05.c",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printint(i);\n  } else {\n    printint(j);\n  }\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input06.c",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printint(i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input07.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input08.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input09.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printint(2 * b - a); }\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input10.c",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; printint(j);\n  i= 10; printint(i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 2; j= j + 1) { printint(j); }\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input11.c",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; printint(i);\n  j= 20; printint(j);\n  k= 30; printint(k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 4; j= j + 1) { printint(j); }\n  for (k= 1;   k <= 5; k= k + 1) { printint(k); }\n  return(i);\n  printint(12345);\n  return(3);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input12.c",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printint(x);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input13.c",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input14.c",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input15.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printint(a);\n  b= &a; c= *b; printint(c);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input16.c",
    "content": "int   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printint(c);\n  e= &c + 1; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input17.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printint(a);\n  e= &d; *e= 12; printint(d);\n  return(0);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input18.c",
    "content": "int main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printint(a);\n  printint(b);\n  return(0);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input18a.c",
    "content": "int   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printint(a);\n  d= &c; *d= 16; printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input19.c",
    "content": "int a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printint(e);\n  return(0);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/input20.c",
    "content": "int a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printint(a);\n  return(0);\n}\n"
  },
  {
    "path": "19_Arrays_pt1/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" ]\n   then\n     cc -o out $i ../lib/printint.c\n     ./out > out.$i\n     rm -f out\n   fi\ndone\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "19_Arrays_pt1/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "19_Arrays_pt1/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "19_Arrays_pt1/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -Wall -o out out.o ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "19_Arrays_pt1/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i=0; i < level; i++) fprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) { Lend = gendumplabel();\n        fprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level+2);\n      dumpAST(n->mid, NOLABEL, level+2);\n      if (n->right) dumpAST(n->right, NOLABEL, level+2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i=0; i < level; i++) fprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level+2);\n      dumpAST(n->right, NOLABEL, level+2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op==A_GLUE) level= -2;\n\n  // General AST node handling\n  if (n->left) dumpAST(n->left, NOLABEL, level+2);\n  if (n->right) dumpAST(n->right, NOLABEL, level+2);\n\n\n  for (int i=0; i < level; i++) fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\"); return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", Gsym[n->v.id].name); return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\"); return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\"); return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\"); return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\"); return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\"); return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\"); return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\"); return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\"); return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\"); return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\"); return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->v.intvalue); return;\n    case A_IDENT:\n      if (n->rvalue)\n        fprintf(stdout, \"A_IDENT rval %s\\n\", Gsym[n->v.id].name);\n      else\n        fprintf(stdout, \"A_IDENT %s\\n\", Gsym[n->v.id].name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\"); return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\"); return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\"); return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", Gsym[n->v.id].name); return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", Gsym[n->v.id].name); return;\n    case A_DEREF:\n      if (n->rvalue)\n        fprintf(stdout, \"A_DEREF rval\\n\");\n      else\n        fprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->v.size); return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "19_Arrays_pt1/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  if (type == P_CHAR || type == P_INT || type == P_LONG)\n    return (1);\n  return (0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  if (type == P_VOIDPTR || type == P_CHARPTR ||\n      type == P_INTPTR || type == P_LONGPTR)\n    return (1);\n  return (0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOID:\n      newtype = P_VOIDPTR;\n      break;\n    case P_CHAR:\n      newtype = P_CHARPTR;\n      break;\n    case P_INT:\n      newtype = P_INTPTR;\n      break;\n    case P_LONG:\n      newtype = P_LONGPTR;\n      break;\n    default:\n      fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOIDPTR:\n      newtype = P_VOID;\n      break;\n    case P_CHARPTR:\n      newtype = P_CHAR;\n      break;\n    case P_INTPTR:\n      newtype = P_INT;\n      break;\n    case P_LONGPTR:\n      newtype = P_LONG;\n      break;\n    default:\n      fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1) \n\treturn (mkastunary(A_SCALE, rtype, tree, rsize));\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/Makefile",
    "content": "SRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g -Wall $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g -Wall $(SRCN)\n\ncomp1arm: $(ARMSRCS)\n\tcc -o comp1arm -g -Wall $(ARMSRCS)\n\tcp comp1arm comp1\n\nclean:\n\trm -f comp1 comp1arm compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: comp1arm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\ntest21: comp1 tests/input21.c lib/printint.c\n\t./comp1 tests/input21.c\n\tcc -o out out.s lib/printint.c\n\t./out\n\narmtest21: comp1arm tests/input21.c lib/printint.c\n\t./comp1 tests/input21.c\n\tcc -o out out.s lib/printint.c\n\t./out\n\ntest21n: compn tests/input21.c lib/printint.c\n\t./compn tests/input21.c\n\tnasm -f elf64 out.s\n\tcc -no-pie -o out lib/printint.c out.o\n\t./out\n"
  },
  {
    "path": "20_Char_Str_Literals/Readme.md",
    "content": "# Part 20: Character and String Literals\n\nI've been wanting to print out \"Hello world\" with our compiler for quite a\nwhile so, now that we have pointers and arrays, it's time in this part of\nthe journey to add character and string literals.\n\nThese are, of course, literal values (i.e. immediately visible). Character\nliterals have the definition of a single character surrounded by single\nquotes. String literals have a sequence of characters surrounded by\ndouble quotes.\n\nNow, seriously, character and string literals in C are just completely\ncrazy. I'm only going to implement the most obvious backslashed-escaped\ncharacters. I'm also going to borrow the character and string literal\nscanning code from SubC to make my life easier.\n\nThis part of the journey is going to be short, but it will end with\n\"Hello world\".\n\n## A New Token\n\nWe need a single new token for our language: T_STRLIT. This is very similar\nto T_IDENT in that the text associated with the token is stored in the\nglobal `Text` and not in the token structure itself.\n\n## Scanning Character Literals\n\nA character literal starts with a single quote, is followed by the\ndefinition of a single character and ends with another single quote.\nThe code to interpret that single character is complicated, so let's\nmodify `scan()` in `scan.c` to call it:\n\n```c\n      case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n        fatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n```\n\nWe can treat a character literal as an integer literal of type `char`;\nthat is, assuming that we limit ourselves to ASCII and don't try to\ndeal with Unicode. That's what I'm doing here.\n\n### The Code for `scanch()`\n\nThe code for the `scanch()`function comes from SubC with a few simplifications:\n\n```c\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':  return '\\a';\n      case 'b':  return '\\b';\n      case 'f':  return '\\f';\n      case 'n':  return '\\n';\n      case 'r':  return '\\r';\n      case 't':  return '\\t';\n      case 'v':  return '\\v';\n      case '\\\\': return '\\\\';\n      case '\"':  return '\"' ;\n      case '\\'': return '\\'';\n      default:\n        fatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);                   // Just an ordinary old character!\n}\n```\n\nThe code recognises most of the escaped character sequences, but it doesn't\ntry to recognise octal character codings or other difficult sequences.\n\n## Scanning String Literals\n\nA string literal starts with a double quote, is followed by zero or more\ncharacters and ends with another double quote. As with character literals,\nwe need to call a separate function in `scan()`:\n\n```c\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token= T_STRLIT;\n      break;\n```\n\nWe create one of the new T_STRLIT and scan the string into the `Text` buffer.\nHere is the code for `scanstr()`:\n\n```c\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i=0; i<TEXTLEN-1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return(i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return(0);\n}\n```\n\nI think the code is straight-forward. It NUL terminates the string that is\nscanned in, and ensures that it doesn't overflow the `Text` buffer. Note\nthat we use the `scanch()` function to scan in individual characters.\n\n## Parsing String Literals\n\nAs I mentioned, character literals are treated as integer literals which\nwe already deal with. Where can we have string literals? Going back to the\n[BNF Grammar for C](https://www.lysator.liu.se/c/ANSI-C-grammar-y.html)\nwritten by Jeff Lee in 1985, we see:\n\n```\nprimary_expression\n        : IDENTIFIER\n        | CONSTANT\n        | STRING_LITERAL\n        | '(' expression ')'\n        ;\n```\n\nand thus we know that we should modify `primary()` in `expr.c`:\n\n```c\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n\n  switch (Token.token) {\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id= genglobstr(Text);\n    n= mkastleaf(A_STRLIT, P_CHARPTR, id);\n    break;\n```\n\nRight now, I'm going to make an anonymous global string. It needs to\nhave all the characters in the string stored in memory, and we also need\na way to refer to it. I don't want to pollute the symbol table with this\nnew string, so I've chosen to allocate a label for the string and store\nthe label's number in the AST node for this string literal. We also need\na new AST node type: A_STRLIT. The label is effectively the base of the\narray of characters in the string, and thus it should be of type P_CHARPTR.\n\nI'll come back to the generation of the assembly output, done by\n`genglobstr()` soon.\n\n### An Example AST Tree\n\nRight now, a string literal is treated as an anonymous pointer. Here's\nthe AST tree for the statement:\n\n```c\n  char *s;\n  s= \"Hello world\";\n\n  A_STRLIT rval label L2\n  A_IDENT s\nA_ASSIGN\n```\n\nThey are both the same type, so there is no need to scale or widen anything.\n\n## Generating the Assembly Output\n\nIn the generic code generator, there are very few changes. We need a function\nto generate the storage for a new string. We need to allocate a label for it\nand then output the string's contents (in `gen.c`):\n\n```c\nint genglobstr(char *strvalue) {\n  int l= genlabel();\n  cgglobstr(l, strvalue);\n  return(l);\n}\n```\n\nAnd we need to recognise the A_STRLIT AST node type and generate assembly\ncode for it. In `genAST()`,\n\n```c\n    case A_STRLIT:\n        return (cgloadglobstr(n->v.id));\n```\n\n## Generating the x86-64 Assembly Output\n\nWe finally get to the actuall new assembly output functions. There are\ntwo: one to generate the string's storage and the other to load the\nbase address of the string.\n\n```c\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr= strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(\\%%rip), %s\\n\", id, reglist[r]);\n  return (r);\n}\n```\n\nGoing back to our example:\n```c\n  char *s;\n  s= \"Hello world\";\n```\n\nThe assembly output for this is:\n\n```\nL2:     .byte   72              # Anonymous string\n        .byte   101\n        .byte   108\n        .byte   108\n        .byte   111\n        .byte   32\n        .byte   119\n        .byte   111\n        .byte   114\n        .byte   108\n        .byte   100\n        .byte   0\n        ...\n        leaq    L2(%rip), %r8   # Load L2's address\n        movq    %r8, s(%rip)    # and store in s\n```\n\n## Miscellaneous Changes\n\nWhen writing the test program for this part of the journey, I uncovered\nanother bug in the existing code. When scaling an integer value to\nmatch the type size that a pointer points to, I forgot to do nothing\nwhen the scale was 1. The code in `modify_type()` in `types.c` is now:\n\n```c\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n        return (mkastunary(A_SCALE, rtype, tree, rsize));\n      else\n        return (tree);          // Size 1, no need to scale\n    }\n```\n\nI'd left the `return (tree)` out, thus returning a NULL tree when\ntrying to scale `char *` pointers.\n\n## Conclusion and What's Next\n\nI'm so glad that we can now output text:\n\n```\n$ make test\n./comp1 tests/input21.c\ncc -o out out.s lib/printint.c\n./out\n10\nHello world\n```\n\nMost of the work this time was extending our lexical scanner to deal\nwith the character and string literal delimiters and the escaping of\ncharacters inside them. But there was some work done on the code\ngenerator, too.\n\nIn the next part of our compiler writing journey, we'll add some\nmore binary operators to the language that the compiler recognises. [Next step](../21_More_Operators/Readme.md)\n"
  },
  {
    "path": "20_Char_Str_Literals/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\nstatic char *dreglist[4] = { \"%r8d\", \"%r9d\", \"%r10d\", \"%r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovzbl\\t%s(\\%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(\\%%rip), %s\\n\", id, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(\\%%rip)\\n\", breglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(\\%%rip)\\n\", dreglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  // Generate the global identity and the label\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"%s:\", Gsym[id].name);\n\n  // Generate the space\n  for (int i=0; i < Gsym[id].size; i++) {\n    switch(typesize) {\n      case 1: fprintf(Outfile, \"\\t.byte\\t0\\n\"); break;\n      case 4: fprintf(Outfile, \"\\t.long\\t0\\n\"); break;\n      case 8: fprintf(Outfile, \"\\t.quad\\t0\\n\"); break;\n      default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr= strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Gsym[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4, 4, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Gsym[id].name);\n  switch(typesize) {\n    case 1: fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Gsym[id].name); break;\n    case 4: fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Gsym[id].name); break;\n    default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\nstatic char *dreglist[4] = { \"r8d\", \"r9d\", \"r10d\", \"r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\tsection\\t.text\\n\"\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r], reglist[r]);\n      fprintf(Outfile, \"\\tmov\\t%s, dword [%s]\\n\", dreglist[r], \n              Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], id);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return(r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  // Generate the global identity and the label\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"%s:\", Gsym[id].name);\n\n  // Generate the space\n  // original version\n  for (int i=0; i < Gsym[id].size; i++) {\n    switch(typesize) {\n      case 1: fprintf(Outfile, \"\\tdb\\t0\\n\"); break;\n      case 4: fprintf(Outfile, \"\\tdd\\t0\\n\"); break;\n      case 8: fprintf(Outfile, \"\\tdq\\t0\\n\"); break;\n      default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(typesize) {\n    case 1: fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", Gsym[id].size); break;\n    case 4: fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", Gsym[id].size); break;\n    case 8: fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", Gsym[id].size); break;\n    default: fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr= strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Gsym[id].name);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, word [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n\nextern_ int O_dumpAST;\n"
  },
  {
    "path": "20_Char_Str_Literals/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      break;\n    case T_INT:\n      type = P_INT;\n      break;\n    case T_LONG:\n      type = P_LONG;\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type\nvoid var_declaration(int type) {\n  int id;\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      id = addglob(Text, pointer_to(type), S_ARRAY, 0, Token.intvalue);\n      genglobsym(id);\n    }\n\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    id = addglob(Text, type, S_VARIABLE, 0, 1);\n    genglobsym(id);\n  }\n\n  // Get the trailing semicolon\n  semi();\n}\n\n//\n// function_declaration: type identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function.\n// The identifier has been scanned & we have the type\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int nameslot, endlabel;\n\n  // Text now has the identifier's name.\n  // Get a label-id for the end label, add the function\n  // to the symbol table, and set the Functionid global\n  // to the function's symbol-id\n  endlabel = genlabel();\n  nameslot = addglob(Text, type, S_FUNCTION, endlabel, 0);\n  Functionid = nameslot;\n\n  // Scan in the parentheses\n  lparen();\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, nameslot));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n       // Parse the function declaration and\n       // generate the assembly code for it\n       tree = function_declaration(type);\n       if (O_dumpAST) { dumpAST(tree, NOLABEL, 0); fprintf(stdout, \"\\n\\n\"); }\n       genAST(tree, NOLABEL, 0);\n    } else {\n\n       // Parse the global variable declaration\n       var_declaration(type);\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(int id);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id);\nint cgloadglobstr(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(int r, int id);\nint cgstorglob(int r, int id);\nvoid cgglobsym(int id);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name, int type, int stype, int endlabel, int size);\n\n// decl.c\nvoid var_declaration(int type);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint parse_type(void);\nint pointer_to(int type);\nint value_at(int type);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "20_Char_Str_Literals/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n  // Operators\n  T_ASSIGN,\n  T_PLUS, T_MINUS,\n  T_STAR, T_SLASH,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_AMPER, T_LOGAND,\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN= 1, A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n#define NOLABEL\t 0\t\t// Use NOLABEL when we have no label to\n\t\t\t\t// pass to genAST()\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n  int size;\t\t\t// Number of elements in the symbol\n};\n"
  },
  {
    "path": "20_Char_Str_Literals/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a function call with a single expression\n// argument and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((id = findglob(Text)) == -1 || Gsym[id].stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Gsym[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and\n// return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  int id;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((id = findglob(Text)) == -1 || Gsym[id].stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, Gsym[id].type, id);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, Gsym[id].type, left, NULL, right, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, 0);\n  return (left);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id= genglobstr(Text);\n    n= mkastleaf(A_STRLIT, P_CHARPTR, id);\n    break;\n\n  case T_IDENT:\n    // This could be a variable, array index or a\n    // function call. Scan in the next token to find out\n    scan(&Token);\n\n\n    // It's a '(', so a function call\n    if (Token.token == T_LPAREN)\n      return (funccall());\n\n    // It's a '[', so an array reference\n    if (Token.token == T_LBRACKET) {\n      return (array_access());\n    }\n    // Not a function call, so reject the new token\n    reject_token(&Token);\n\n    // Check that the variable exists.\n    id = findglob(Text);\n    if (id == -1 || Gsym[id].stype != S_VARIABLE)\n      fatals(\"Unknown variable\", Text);\n\n    // Make a leaf AST node for it\n    n = mkastleaf(A_IDENT, Gsym[id].type, id);\n    break;\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype < T_INTLIT)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10,\t\t\t// T_EOF,  T_ASSIGN\n  20, 20,\t\t\t// T_PLUS, T_MINUS\n  30, 30,\t\t\t// T_STAR, T_SLASH\n  40, 40,\t\t\t// T_EQ, T_NE\n  50, 50, 50, 50\t\t// T_LT, T_GT, T_LE, T_GE\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype >= T_VOID)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*' prefix_expression\n//     | '&' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN || tokentype == T_RBRACKET) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (left == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(binastop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon, ')' or ']', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN\n\t|| tokentype == T_RBRACKET) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOLABEL, n->op);\n      genfreeregs();\n      genAST(n->right, NOLABEL, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->v.id);\n      genAST(n->left, NOLABEL, n->op);\n      cgfuncpostamble(n->v.id);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue, n->type));\n    case A_STRLIT:\n        return (cgloadglobstr(n->v.id));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop== A_DEREF)\n        return (cgloadglob(n->v.id));\n      else\n        return (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n        case A_IDENT: return (cgstorglob(leftreg, n->right->v.id));\n\tcase A_DEREF: return (cgstorderef(leftreg, rightreg, n->right->type));\n        default: fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_FUNCCALL:\n      return (cgcall(leftreg, n->v.id));\n    case A_ADDR:\n      return (cgaddress(n->v.id));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n        return (cgderef(leftreg, n->left->type));\n      else\n        return (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->v.size) {\n\tcase 2: return(cgshlconst(leftreg, 1));\n\tcase 4: return(cgshlconst(leftreg, 2));\n\tcase 8: return(cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n          rightreg= cgloadint(n->v.size, P_INT);\n          return (cgmul(leftreg, rightreg));\n      }\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genglobstr(char *strvalue) {\n  int l= genlabel();\n  cgglobstr(l, strvalue);\n  return(l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n\nvoid printchar(long x) {\n  putc((char)(x & 0x7f), stdout);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n  Globs = 0;\n  O_dumpAST = 0;\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-T] infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nint main(int argc, char *argv[]) {\n  int i;\n\n  // Initialise the globals\n  init();\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    if (*argv[i] != '-')\n      break;\n    for (int j = 1; argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have an input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Open up the input file\n  if ((Infile = fopen(argv[i], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[i], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n  // For now, ensure that printint() and printchar() are defined\n  addglob(\"printint\", P_INT, S_FUNCTION, 0, 0);\n  addglob(\"printchar\", P_VOID, S_FUNCTION, 0, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  return (0);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i=0; i<TEXTLEN-1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return(i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return(0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      t->token = T_PLUS;\n      break;\n    case '-':\n      t->token = T_MINUS;\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tfatalc(\"Unrecognised character\", c);\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token= T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Ensure\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    fatal(\"Bad comparison operator\");\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Gsym[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Gsym[Functionid].type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration.\n      // XXX: These are globals at present.\n      type = parse_type();\n      ident();\n      var_declaration(type);\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + endlabel: if this is a function\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int endlabel, int size) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  Gsym[y].type = type;\n  Gsym[y].stype = stype;\n  Gsym[y].endlabel = endlabel;\n  Gsym[y].size = size;\n  return (y);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input01.c",
    "content": "void main()\n{ printint(12 * 3);\n  printint(18 - 2 * 4);\n  printint(1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input02.c",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printint(fred + jim);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input03.c",
    "content": "void main()\n{\n  int x;\n  x= 1;     printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input04.c",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  printint(x);\n  x= 7 <= 9; printint(x);\n  x= 7 != 9; printint(x);\n  x= 7 == 7; printint(x);\n  x= 7 >= 7; printint(x);\n  x= 7 <= 7; printint(x);\n  x= 9 > 7;  printint(x);\n  x= 9 >= 7; printint(x);\n  x= 9 != 7; printint(x);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input05.c",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printint(i);\n  } else {\n    printint(j);\n  }\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input06.c",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printint(i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input07.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input08.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input09.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printint(2 * b - a); }\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input10.c",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; printint(j);\n  i= 10; printint(i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 2; j= j + 1) { printint(j); }\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input11.c",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; printint(i);\n  j= 20; printint(j);\n  k= 30; printint(k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 4; j= j + 1) { printint(j); }\n  for (k= 1;   k <= 5; k= k + 1) { printint(k); }\n  return(i);\n  printint(12345);\n  return(3);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input12.c",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printint(x);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input13.c",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input14.c",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input15.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printint(a);\n  b= &a; c= *b; printint(c);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input16.c",
    "content": "int   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printint(c);\n  e= &c + 1; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input17.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printint(a);\n  e= &d; *e= 12; printint(d);\n  return(0);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input18.c",
    "content": "int main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printint(a);\n  printint(b);\n  return(0);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input18a.c",
    "content": "int   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printint(a);\n  d= &c; *d= 16; printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input19.c",
    "content": "int a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printint(e);\n  return(0);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input20.c",
    "content": "int a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printint(a);\n  return(0);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/input21.c",
    "content": "char  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printint(c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printchar(*str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" ]\n   then\n     cc -o out $i ../lib/printint.c\n     ./out > out.$i\n     rm -f out\n   fi\ndone\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "20_Char_Str_Literals/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -Wall -o out out.o ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "20_Char_Str_Literals/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i=0; i < level; i++) fprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) { Lend = gendumplabel();\n        fprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level+2);\n      dumpAST(n->mid, NOLABEL, level+2);\n      if (n->right) dumpAST(n->right, NOLABEL, level+2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i=0; i < level; i++) fprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level+2);\n      dumpAST(n->right, NOLABEL, level+2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op==A_GLUE) level= -2;\n\n  // General AST node handling\n  if (n->left) dumpAST(n->left, NOLABEL, level+2);\n  if (n->right) dumpAST(n->right, NOLABEL, level+2);\n\n\n  for (int i=0; i < level; i++) fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\"); return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", Gsym[n->v.id].name); return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\"); return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\"); return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\"); return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\"); return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\"); return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\"); return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\"); return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\"); return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\"); return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\"); return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->v.intvalue); return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->v.id); return;\n    case A_IDENT:\n      if (n->rvalue)\n        fprintf(stdout, \"A_IDENT rval %s\\n\", Gsym[n->v.id].name);\n      else\n        fprintf(stdout, \"A_IDENT %s\\n\", Gsym[n->v.id].name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\"); return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\"); return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\"); return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", Gsym[n->v.id].name); return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", Gsym[n->v.id].name); return;\n    case A_DEREF:\n      if (n->rvalue)\n        fprintf(stdout, \"A_DEREF rval\\n\");\n      else\n        fprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->v.size); return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "20_Char_Str_Literals/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  if (type == P_CHAR || type == P_INT || type == P_LONG)\n    return (1);\n  return (0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  if (type == P_VOIDPTR || type == P_CHARPTR ||\n      type == P_INTPTR || type == P_LONGPTR)\n    return (1);\n  return (0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOID:\n      newtype = P_VOIDPTR;\n      break;\n    case P_CHAR:\n      newtype = P_CHARPTR;\n      break;\n    case P_INT:\n      newtype = P_INTPTR;\n      break;\n    case P_LONG:\n      newtype = P_LONGPTR;\n      break;\n    default:\n      fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOIDPTR:\n      newtype = P_VOID;\n      break;\n    case P_CHARPTR:\n      newtype = P_CHAR;\n      break;\n    case P_INTPTR:\n      newtype = P_INT;\n      break;\n    case P_LONGPTR:\n      newtype = P_LONG;\n      break;\n    default:\n      fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "21_More_Operators/Makefile",
    "content": "SRCS= defs.h cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nSRCN= defs.h cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nARMSRCS= defs.h cg_arm.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\ncomp1: $(SRCS)\n\tcc -o comp1 -g -Wall $(SRCS)\n\ncompn: $(SRCN)\n\tcc -o compn -g -Wall $(SRCN)\n\ncomp1arm: $(ARMSRCS)\n\tcc -o comp1arm -g -Wall $(ARMSRCS)\n\tcp comp1arm comp1\n\nclean:\n\trm -f comp1 comp1arm compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: comp1arm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "21_More_Operators/Readme.md",
    "content": "# Part 21: More Operators\n\nIn this part of our compiler writing journey, I decided to pick some\nlow-hanging fruit and implement many of the expression operators which\nare still missing. These include:\n\n+ `++` and `--`, both pre-increment/decrement and post--increment/decrement\n+ unary `-`, `~`, and `!`\n+ binary `^`, `&`, `|`, `<<` and `>>`\n\nI also implemented the implicit \"not zero operator\" which treats an\nexpression rvalue as a boolean value for selection and loop statements, e.g.\n\n```c\n  for (str= \"Hello\"; *str; str++) ...\n```\n\ninstead of writing\n\n```c\n  for (str= \"Hello\"; *str != 0; str++) ...\n```\n\n## Tokens and Scanning\n\nAs always, we start off with any new tokens in the language. There are\na few this time:\n\n| Scanned Input | Token |\n|:-------------:|-------|\n|   <code>&#124;&#124;</code>        | T_LOGOR |\n|   `&&`        | T_LOGAND |\n|   <code>&#124;</code>         | T_OR |\n|   `^`         | T_XOR |\n|   `<<`        | T_LSHIFT |\n|   `>>`        | T_RSHIFT |\n|   `++`        | T_INC |\n|   `--`        | T_DEC |\n|   `~`         | T_INVERT |\n|   `!`         | T_LOGNOT |\n\nSome of these are composed of new single characters, so the scanning of\nthese is easy. For others, we need to distinguish between single characters\nand pairs of different characters. An example is `<`, `<<` and `<=`. We\nhave already seen how to do the scanning for these in `scan.c`, so I won't\ngive the new code here. Browse through `scan.c` to see the additions.\n\n## Adding the Binary Operators to the Parsing\n\nNow we need to parse these operators. Some of these operators are binary\noperators: `||`, `&&`, `|`, `^`, `<<` and `>>`. We already have a precedence\nframework in place for binary operators. We can simply add the new operators\nto the framework.\n\nWhen I did this, I realised that I had several of the existing operators in\nwith the wrong precedence according to\n[this table of C operator precedence](https://en.cppreference.com/w/c/language/operator_precedence). We also need to align the AST node operations with the\nset of binary operator tokens. Thus, here are the definitions of the\ntokens, the AST node types and the operator precedence table from `defs.h`\nand `expr.c`:\n\n```c\n// Token types\nenum {\n  T_EOF,\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND, \n  T_OR, T_XOR, T_AMPER, \n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n  ...\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN= 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  ...\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT,\n  ...\n};\n\n// Operator precedence for each binary token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,                // T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,                   // T_OR, T_XOR, T_AMPER \n  70, 70,                       // T_EQ, T_NE\n  80, 80, 80, 80,               // T_LT, T_GT, T_LE, T_GE\n  90, 90,                       // T_LSHIFT, T_RSHIFT\n  100, 100,                     // T_PLUS, T_MINUS\n  110, 110                      // T_STAR, T_SLASH\n};\n```\n\n## New Unary Operators.\n\nNow we get to the parsing of the new unary operators, `++`, `--`, `~` and \n`!`. All of these are prefix operators (i.e. before an expression), but\nthe `++` and `--` operators can also be postfix operators. Thus, we'll\nneed to parse three prefix and two postfix operators, and perform five\ndifferent semantic actions for them.\n\nTo prepare for this addition of these new operators, I went back and\nconsulted the\n[BNF Grammar for C](https://www.lysator.liu.se/c/ANSI-C-grammar-y.html).\nAs these new operators can't be worked into the existing binary operator\nframework, we'll need to implement them with new functions in our \nrecursive descent parser. Here are the *relevant* sections from the above\ngrammar, rewritten to use our token names:\n\n```\nprimary_expression\n        : T_IDENT\n        | T_INTLIT\n        | T_STRLIT\n        | '(' expression ')'\n        ;\n\npostfix_expression\n        : primary_expression\n        | postfix_expression '[' expression ']'\n        | postfix_expression '(' expression ')'\n        | postfix_expression '++'\n        | postfix_expression '--'\n        ;\n\nprefix_expression\n        : postfix_expression\n        | '++' prefix_expression\n        | '--' prefix_expression\n        | prefix_operator prefix_expression\n        ;\n\nprefix_operator\n        : '&'\n        | '*'\n        | '-'\n        | '~'\n        | '!'\n        ;\n\nmultiplicative_expression\n        : prefix_expression\n        | multiplicative_expression '*' prefix_expression\n        | multiplicative_expression '/' prefix_expression\n        | multiplicative_expression '%' prefix_expression\n        ;\n\n        etc.\n```\n\nWe implement the binary operators in `binexpr()` in `expr.c`, but this calls\n`prefix()`, just as `multiplicative_expression` in the above BNF grammar\nrefers to `prefix_expression`. We already have a function called `primary()`.\nNow we need a function, `postfix()` to deal with the postfix expressions.\n\n## Prefix Operators\n\nWe already parse a couple of tokens in `prefix()`: T_AMPER and T_STAR. We\ncan add in the new tokens here (T_MINUS, T_INVERT, T_LOGNOT, T_INC and\nT_DEC) by adding more case statements to the `switch (Token.token)` statement.\n\nI won't include the code here because all the cases have a similar structure:\n\n  + Skip past the token with `scan(&Token)`\n  + Parse the next expression with `prefix()`\n  + Do some semantic checking\n  + Extend the AST tree that was returned by `prefix()`\n\nHowever, the differences between some of the cases are important to cover.\nFor the parsing of the `&` (T_AMPER) token, the expression needs to\nbe treated as an lvalue: if we do `&x`, we want the address of the variable\n`x`, not the address of `x`'s value. Other cases do need to have the\nAST tree returned by `prefix()` forced to be an rvalue:\n\n  + `-` (T_MINUS)\n  + `~` (T_INVERT)\n  + `!` (T_LOGNOT)\n\nAnd, for the pre-increment and pre-decrement operators, we actually *require*\nthe expression to be an lvalue: we can do `++x` but not `++3`. For now,\nI've written the code to require a simple identifier, but I know later on\nwe will want to parse and deal with `++b[2]` and `++ *ptr`.\n\nAlso, from a design point of view, we have the option of altering the\nAST tree returned by `prefix()` (with no new AST nodes), or adding one\nor more new AST nodes to the tree:\n\n  + T_AMPER modifies the existing AST tree so the root is A_ADDR\n  + T_STAR adds an A_DEREF node to the root of the tree\n  + T_STAR adds an A_NEGATE node to the root of the tree after\n    possibly widening the tree to be an `int` value. Why? Because the\n    tree might be of type `char` which is unsigned, and you can't negate\n    an unsigned value.\n  + T_INVERT adds an A_INVERT node to the root of the tree\n  + T_LOGNOT adds an A_LOGNOT node to the root of the tree\n  + T_INC adds an A_PREINC node to the root of the tree\n  + T_DEC adds an A_PREDEC node to the root of the tree\n\n## Parsing the Postfix Operators\n\nIf you look at the BNF grammar I hyperlinked to above, to parse a postfix\nexpression we need to refer to the parsing of a primary expression. To\nimplement this, we need to get the tokens of the primary expression first\nand then then determine if there are any trailing postfix tokens.\n\nEven though the grammar shows \"postfix\" calling \"primary\", I've\nimplemented it by scanning the tokens in `primary()` and then deciding to call\n`postfix()` to parse the postfix tokens.\n\n> This turned out to be a mistake -- Warren, writing from the future.\n\nThe BNF grammar above seems to allow expressions like `x++ ++` because it has:\n\n```\npostfix_expression:\n        postfix_expression '++'\n        ;\n```\n\nbut I'm not going to allow more than one postfix operator after the\nexpression. So let's look at the new code:\n\n`primary()` deals with recognising primary expressions: integer literals,\nstring literals and identifiers. It also recognises parenthesised expressions.\nOnly the identifiers can be followed by postfix operators.\n\n```c\nstatic struct ASTnode *primary(void) {\n  ...\n  switch (Token.token) {\n    case T_INTLIT: ...\n    case T_STRLIT: ...\n    case T_LPAREN: ...\n    case T_IDENT:\n      return (postfix());\n    ...\n}\n```\n\nI've moved the parsing of function calls and array references out to\n`postfix()`, and this is where we parse the postfix `++` and `--` operators:\n\n```c\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  int id;\n\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n\n  // A variable. Check that the variable exists.\n  id = findglob(Text);\n  if (id == -1 || Gsym[id].stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n      // Post-increment: skip over the token\n    case T_INC:\n      scan(&Token);\n      n = mkastleaf(A_POSTINC, Gsym[id].type, id);\n      break;\n\n      // Post-decrement: skip over the token\n    case T_DEC:\n      scan(&Token);\n      n = mkastleaf(A_POSTDEC, Gsym[id].type, id);\n      break;\n\n      // Just a variable reference\n    default:\n      n = mkastleaf(A_IDENT, Gsym[id].type, id);\n  }\n  return (n);\n}\n```\n\nAnother design decision. For `++`, we could have made an A_IDENT AST\nnode with an A_POSTINC parent, but given that we have the identifier's name\nin `Text`, we can build a single AST node that contains both the node type\nand the reference to the identifier's slot number in the symbol table.\n\n## Converting an Integer Expression to a Boolean Value\n\nBefore we leave the parsing side of things and move to the code generation\nside of things, I should mention the change I made to allow integer\nexpressions to be treated as boolean expressions, e.g.\n\n```\n  x= a + b;\n  if (x) { printf(\"x is not zero\\n\"); }\n```\n\nThe BNF grammar doesn't provide any explicit syntax rules to restrict\nexpressions to be boolean, e.g:\n\n```\nselection_statement\n        : IF '(' expression ')' statement\n```\n\nTherefore, we'll have to do this semantically. In `stmt.c` where I parse\nIF, WHILE and FOR loops, I've added this code:\n\n```c\n  // Parse the following expression\n  // Force a non-comparison expression to be boolean\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n```\n\nI've introduced a new AST node type, A_TOBOOL. This will generate code\nto take any integer value. If this value is zero, the result is zero,\notherwise the result will be one.\n\n## Generating the Code for the New Operators\n\nNow we turn our attention to generating the code for the new operators.\nActually, the new AST node types: A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\nA_LSHIFT, A_RSHIFT, A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\nA_NEGATE, A_INVERT, A_LOGNOT and A_TOBOOL.\n\nAll of these are simple calls out to matching functions in the\nplatform-specific code generator in `cg.c`. So the new code in `genAST()`\nin `gen.c` is simply:\n\n```c\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_POSTINC:\n      // Load the variable's value into a register,\n      // then increment it\n      return (cgloadglob(n->v.id, n->op));\n    case A_POSTDEC:\n      // Load the variable's value into a register,\n      // then decrement it\n      return (cgloadglob(n->v.id, n->op));\n    case A_PREINC:\n      // Load and increment the variable's value into a register\n      return (cgloadglob(n->left->v.id, n->op));\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      return (cgloadglob(n->left->v.id, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, label));\n```\n\n## x86-64 Specific Code Generation Functions\n\nThat means we can now look at the back-end functions to generate real x86-64\nassembly code. For most of the bitwise operations, the x86-64 platform\nhas assembly instructions to do them:\n\n```c\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1); return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1); return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1); return (r2);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]); return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]); return (r);\n}\n```\n\nWith the shift operations, as far as I can tell the shift amount has to\nbe loaded into the `%cl` register first.\n\n```c\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2); return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2); return (r1);\n}\n```\n\nThe operations that deal with boolean expressions (where the result\nmust be either 0 or 1) are a bit more complicated.\n\n```c\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n```\n\nThe `test` instruction essentially AND's the register with itself to set\nthe zero and negative flags. Then we set the register to 1 if it is\nequal to zero (`sete`). Then we move this 8-bit result into the 64-bit\nregister proper.\n\nAnd here is the code to convert an integer into a boolean value:\n\n```c\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n```\n\nAgain, we do a `test` to get the zero-ness or non-zeroeness of the register.\nIf we are doing this for an selection or loop statement, then `je` to jump\nif the result was false. Otherwise, use `setnz` to set the register to 1\nif it was non-zero originally.\n\n## Increment and Decrement Operations\n\nI've left the `++` and `--` operations to last. The subtlety here is that\nwe have to both get the value out of the memory location into a register,\nand separately increment or decrement it. And we have to choose to do this\nbefore or after we load the register.\n\nAs we already have a `cgloadglob()` function to load a global variable's\nvalue, let's modify it to also alter the variable as required. The code\nis ugly but it does work.\n\n```c\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tincb\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdecb\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tincb\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdecb\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tincl\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdecl\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      fprintf(Outfile, \"\\tmovslq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tincl\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdecl\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tincq\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdecq\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tincq\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdecq\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n```\n\nI'm pretty sure that I'll have to rewrite this later on to perform\n`x= b[5]++`, but this will do for now. After all, baby steps is what\nI promised for each step of our journey.\n\n## Testing the New Functionality\n\nI won't go through the new test input files in detail for this step.\nThey are `input22.c`, `input23.c` and `input24.c` in the `tests` directory.\nYou can browse them and confirm that the compiler can correctly compile\nthem:\n\n```\n$ make test\n...\ninput22.c: OK\ninput23.c: OK\ninput24.c: OK\n```\n\n## Conclusion and What's Next\n\nIn terms of extending the functionality of our compiler, this part of\nthe journey added a lot of functionality, but I hope the amount of\nadditional conceptual complexity was minimal.\n\nWe added a bunch of binary operators and this was done by updating\nthe scanner and changing the operator precedence table.\n\nFor the unary operators, we added them manually to the parser in the\n`prefix()` function.\n\nFor the new postfix operators, we separated the old function call and\narray index functionality out into a new `postfix()` function, and\nused this to add in the postfix operators. We did have to worry a bit\nabout lvalues and rvalues here. We also had some design decisions about\nwhat AST nodes to add, or if we should just redecorate some existing\nAST nodes.\n\nThe code generation ended up being relatively simple because the x86-64\narchitecture has instructions to implement the operations we needed.\nHowever, we did have to set up some specific registers for some of the\noperations, or perform instruction combinations to do what we wanted.\n\nThe tricky operations were the increment and decrement operations. I've\nput code in to get these to work for ordinary variables but we will have to\nrevisit this later.\n\nIn the next part of our compiler writing journey, I'd like to\ntackle local variables. Once we can get these to work, we can extend\nthem to also include function parameters and arguments. This will\ntake two or more steps. [Next step](../22_Design_Locals/Readme.md)\n"
  },
  {
    "path": "21_More_Operators/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[4] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\nstatic char *dreglist[4] = { \"%r8d\", \"%r9d\", \"%r10d\", \"%r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      fprintf(Outfile, \"\\tmovslq\\t%s(\\%%rip), %s\\n\", Gsym[id].name,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincq\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecq\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      fprintf(Outfile, \"\\tmovq\\t%s(\\%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincq\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecq\\t%s(\\%%rip)\\n\", Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(\\%%rip), %s\\n\", id, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(\\%%rip)\\n\", breglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(\\%%rip)\\n\", dreglist[r],\n\t      Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s, %s(\\%%rip)\\n\", reglist[r], Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  // Generate the global identity and the label\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"%s:\", Gsym[id].name);\n\n  // Generate the space\n  for (int i = 0; i < Gsym[id].size; i++) {\n    switch (typesize) {\n      case 1:\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"\\t.long\\t0\\n\");\n\tbreak;\n      case 8:\n\tfprintf(Outfile, \"\\t.quad\\t0\\n\");\n\tbreak;\n      default:\n\tfatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Gsym[id].name, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "21_More_Operators/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Gsym[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Gsym[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4, 4, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Gsym[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Gsym[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Gsym[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "21_More_Operators/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\nstatic int freereg[4];\nstatic char *reglist[4]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[4] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\nstatic char *dreglist[4] = { \"r8d\", \"r9d\", \"r10d\", \"r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Gsym[id].name;\n  fprintf(Outfile,\n\t  \"\\tsection\\t.text\\n\"\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Gsym[id].endlabel);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Gsym[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Gsym[id].name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Gsym[id].name);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Gsym[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Gsym[id].name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Gsym[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Gsym[id].name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              Gsym[id].name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Gsym[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Gsym[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Gsym[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Gsym[id].name);\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Gsym[id].name);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Gsym[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Gsym[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], id);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Gsym[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Gsym[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Gsym[id].type);\n\n  // Generate the global identity and the label\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", Gsym[id].name);\n  fprintf(Outfile, \"%s:\", Gsym[id].name);\n\n  // Generate the space\n  // original version\n  for (int i = 0; i < Gsym[id].size; i++) {\n    switch(typesize) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(typesize) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", Gsym[id].size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", Gsym[id].size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", Gsym[id].size);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Gsym[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Gsym[id].type);\n  }\n  cgjump(Gsym[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Gsym[id].name);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", reglist[r], dreglist[r]);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "21_More_Operators/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Gsym[NSYMBOLS];\t// Global symbol table\n\nextern_ int O_dumpAST;\n"
  },
  {
    "path": "21_More_Operators/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      break;\n    case T_INT:\n      type = P_INT;\n      break;\n    case T_LONG:\n      type = P_LONG;\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type\nvoid var_declaration(int type) {\n  int id;\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      id = addglob(Text, pointer_to(type), S_ARRAY, 0, Token.intvalue);\n      genglobsym(id);\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    id = addglob(Text, type, S_VARIABLE, 0, 1);\n    genglobsym(id);\n  }\n\n  // Get the trailing semicolon\n  semi();\n}\n\n//\n// function_declaration: type identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function.\n// The identifier has been scanned & we have the type\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int nameslot, endlabel;\n\n  // Text now has the identifier's name.\n  // Get a label-id for the end label, add the function\n  // to the symbol table, and set the Functionid global\n  // to the function's symbol-id\n  endlabel = genlabel();\n  nameslot = addglob(Text, type, S_FUNCTION, endlabel, 0);\n  Functionid = nameslot;\n\n  // Scan in the parentheses\n  lparen();\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, nameslot));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration and\n      // generate the assembly code for it\n      tree = function_declaration(type);\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n    } else {\n\n      // Parse the global variable declaration\n      var_declaration(type);\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "21_More_Operators/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(int id);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id, int op);\nint cgloadglobstr(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(int r, int id);\nint cgstorglob(int r, int id);\nvoid cgglobsym(int id);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint addglob(char *name, int type, int stype, int endlabel, int size);\n\n// decl.c\nvoid var_declaration(int type);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint parse_type(void);\nint pointer_to(int type);\nint value_at(int type);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "21_More_Operators/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND, \n  T_OR, T_XOR, T_AMPER, \n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN= 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n#define NOLABEL\t 0\t\t// Use NOLABEL when we have no label to\n\t\t\t\t// pass to genAST()\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n  int size;\t\t\t// Number of elements in the symbol\n};\n"
  },
  {
    "path": "21_More_Operators/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a function call with a single expression\n// argument and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((id = findglob(Text)) == -1 || Gsym[id].stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Gsym[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and\n// return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  int id;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((id = findglob(Text)) == -1 || Gsym[id].stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, Gsym[id].type, id);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, Gsym[id].type, left, NULL, right, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  int id;\n\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // A variable. Check that the variable exists.\n  id = findglob(Text);\n  if (id == -1 || Gsym[id].stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n      // Post-increment: skip over the token\n    case T_INC:\n      scan(&Token);\n      n = mkastleaf(A_POSTINC, Gsym[id].type, id);\n      break;\n\n      // Post-decrement: skip over the token\n    case T_DEC:\n      scan(&Token);\n      n = mkastleaf(A_POSTDEC, Gsym[id].type, id);\n      break;\n\n      // Just a variable reference\n    default:\n      n = mkastleaf(A_IDENT, Gsym[id].type, id);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n\tn = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n      break;\n\n    case T_STRLIT:\n      // For a STRLIT token, generate the assembly for it.\n      // Then make a leaf AST node for it. id is the string's label.\n      id = genglobstr(Text);\n      n = mkastleaf(A_STRLIT, P_CHARPTR, id);\n      break;\n\n    case T_IDENT:\n      return (postfix());\n\n    case T_LPAREN:\n      // Beginning of a parenthesised expression, skip the '('.\n      // Scan in the expression and the right parenthesis\n      scan(&Token);\n      n = binexpr(0);\n      rparen();\n      return (n);\n\n    default:\n      fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n    case T_AMPER:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Ensure that it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"& operator must be followed by an identifier\");\n\n      // Now change the operator to A_ADDR and the type to\n      // a pointer to the original type\n      tree->op = A_ADDR;\n      tree->type = pointer_to(tree->type);\n      break;\n    case T_STAR:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's either another deref or an\n      // identifier\n      if (tree->op != A_IDENT && tree->op != A_DEREF)\n\tfatal(\"* operator must be followed by an identifier or *\");\n\n      // Prepend an A_DEREF operation to the tree\n      tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n      break;\n    case T_MINUS:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_NEGATE operation to the tree and\n      // make the child an rvalue. Because chars are unsigned,\n      // also widen this to int so that it's signed\n      tree->rvalue = 1;\n      tree = modify_type(tree, P_INT, 0);\n      tree = mkastunary(A_NEGATE, tree->type, tree, 0);\n      break;\n    case T_INVERT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_INVERT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_INVERT, tree->type, tree, 0);\n      break;\n    case T_LOGNOT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_LOGNOT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_LOGNOT, tree->type, tree, 0);\n      break;\n    case T_INC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"++ operator must be followed by an identifier\");\n\n      // Prepend an A_PREINC operation to the tree\n      tree = mkastunary(A_PREINC, tree->type, tree, 0);\n      break;\n    case T_DEC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"-- operator must be followed by an identifier\");\n\n      // Prepend an A_PREDEC operation to the tree\n      tree = mkastunary(A_PREDEC, tree->type, tree, 0);\n      break;\n    default:\n      tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN || tokentype == T_RBRACKET) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (left == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(binastop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon, ')' or ']', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN\n\t|| tokentype == T_RBRACKET) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "21_More_Operators/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOLABEL, n->op);\n      genfreeregs();\n      genAST(n->right, NOLABEL, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->v.id);\n      genAST(n->left, NOLABEL, n->op);\n      cgfuncpostamble(n->v.id);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->v.id));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF)\n\treturn (cgloadglob(n->v.id, n->op));\n      else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  return (cgstorglob(leftreg, n->right->v.id));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_FUNCCALL:\n      return (cgcall(leftreg, n->v.id));\n    case A_ADDR:\n      return (cgaddress(n->v.id));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->v.size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->v.size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n      // Load the variable's value into a register,\n      // then increment it\n      return (cgloadglob(n->v.id, n->op));\n    case A_POSTDEC:\n      // Load the variable's value into a register,\n      // then decrement it\n      return (cgloadglob(n->v.id, n->op));\n    case A_PREINC:\n      // Load and increment the variable's value into a register\n      return (cgloadglob(n->left->v.id, n->op));\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      return (cgloadglob(n->left->v.id, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, label));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "21_More_Operators/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n\nvoid printchar(long x) {\n  putc((char)(x & 0x7f), stdout);\n}\n"
  },
  {
    "path": "21_More_Operators/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n  Globs = 0;\n  O_dumpAST = 0;\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-T] infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nint main(int argc, char *argv[]) {\n  int i;\n\n  // Initialise the globals\n  init();\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    if (*argv[i] != '-')\n      break;\n    for (int j = 1; argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have an input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Open up the input file\n  if ((Infile = fopen(argv[i], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[i], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n  // For now, ensure that printint() and printchar() are defined\n  addglob(\"printint\", P_INT, S_FUNCTION, 0, 0);\n  addglob(\"printchar\", P_VOID, S_FUNCTION, 0, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  return (0);\n}\n"
  },
  {
    "path": "21_More_Operators/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "21_More_Operators/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "21_More_Operators/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Gsym[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Gsym[Functionid].type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration.\n      // XXX: These are globals at present.\n      type = parse_type();\n      ident();\n      var_declaration(type);\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "21_More_Operators/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Gsym[i].name && !strcmp(s, Gsym[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= NSYMBOLS)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Add a global symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + endlabel: if this is a function\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int endlabel, int size) {\n  int y;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((y = findglob(name)) != -1)\n    return (y);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  y = newglob();\n  Gsym[y].name = strdup(name);\n  Gsym[y].type = type;\n  Gsym[y].stype = stype;\n  Gsym[y].endlabel = endlabel;\n  Gsym[y].size = size;\n  return (y);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input01.c",
    "content": "void main()\n{ printint(12 * 3);\n  printint(18 - 2 * 4);\n  printint(1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input02.c",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printint(fred + jim);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input03.c",
    "content": "void main()\n{\n  int x;\n  x= 1;     printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input04.c",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  printint(x);\n  x= 7 <= 9; printint(x);\n  x= 7 != 9; printint(x);\n  x= 7 == 7; printint(x);\n  x= 7 >= 7; printint(x);\n  x= 7 <= 7; printint(x);\n  x= 9 > 7;  printint(x);\n  x= 9 >= 7; printint(x);\n  x= 9 != 7; printint(x);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input05.c",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printint(i);\n  } else {\n    printint(j);\n  }\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input06.c",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printint(i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input07.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input08.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input09.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printint(2 * b - a); }\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input10.c",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; printint(j);\n  i= 10; printint(i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 2; j= j + 1) { printint(j); }\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input11.c",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; printint(i);\n  j= 20; printint(j);\n  k= 30; printint(k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 4; j= j + 1) { printint(j); }\n  for (k= 1;   k <= 5; k= k + 1) { printint(k); }\n  return(i);\n  printint(12345);\n  return(3);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input12.c",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printint(x);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input13.c",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input14.c",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input15.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printint(a);\n  b= &a; c= *b; printint(c);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input16.c",
    "content": "int   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printint(c);\n  e= &c + 1; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input17.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printint(a);\n  e= &d; *e= 12; printint(d);\n  return(0);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input18.c",
    "content": "int main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printint(a);\n  printint(b);\n  return(0);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input18a.c",
    "content": "int   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printint(a);\n  d= &c; *d= 16; printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input19.c",
    "content": "int a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printint(e);\n  return(0);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input20.c",
    "content": "int a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printint(a);\n  return(0);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input21.c",
    "content": "char  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printint(c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printchar(*str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input22.c",
    "content": "char a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printint(a);\n  e= 5; f= 7; d= e + f++; printint(d);\n  h= 5; i= 7; g= h + i++; printint(g);\n  a= b-- + c; printint(a);\n  d= e-- + f; printint(d);\n  g= h-- + i; printint(g);\n  a= ++b + c; printint(a);\n  d= ++e + f; printint(d);\n  g= ++h + i; printint(g);\n  a= b * --c; printint(a);\n  d= e * --f; printint(d);\n  g= h * --i; printint(g);\n  return(0);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input23.c",
    "content": "char *str;\nint   x;\n\nint main() {\n  x= -23; printint(x);\n  printint(-10 * -10);\n\n  x= 1; x= ~x; printint(x);\n\n  x= 2 > 5; printint(x);\n  x= !x; printint(x);\n  x= !x; printint(x);\n\n  x= 13; if (x) { printint(13); }\n  x= 0; if (!x) { printint(14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printchar(*str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/input24.c",
    "content": "int a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printint(a & b);\n  printint(a | b);\n  printint(a ^ b);\n  printint(1 << 3);\n  printint(63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "21_More_Operators/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" ]\n   then\n     cc -o out $i ../lib/printint.c\n     ./out > out.$i\n     rm -f out\n   fi\ndone\n"
  },
  {
    "path": "21_More_Operators/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "21_More_Operators/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "21_More_Operators/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "21_More_Operators/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "21_More_Operators/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "21_More_Operators/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "21_More_Operators/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "21_More_Operators/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "21_More_Operators/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "21_More_Operators/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "21_More_Operators/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "21_More_Operators/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "21_More_Operators/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "21_More_Operators/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "21_More_Operators/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "21_More_Operators/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "21_More_Operators/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "21_More_Operators/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "21_More_Operators/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "21_More_Operators/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "21_More_Operators/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "21_More_Operators/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "21_More_Operators/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "21_More_Operators/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "21_More_Operators/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "21_More_Operators/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "21_More_Operators/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -Wall -o out out.o ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "21_More_Operators/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", Gsym[n->v.id].name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->v.intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->v.id);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", Gsym[n->v.id].name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", Gsym[n->v.id].name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", Gsym[n->v.id].name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", Gsym[n->v.id].name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->v.size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", Gsym[n->v.id].name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", Gsym[n->v.id].name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "21_More_Operators/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  if (type == P_CHAR || type == P_INT || type == P_LONG)\n    return (1);\n  return (0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  if (type == P_VOIDPTR || type == P_CHARPTR ||\n      type == P_INTPTR || type == P_LONGPTR)\n    return (1);\n  return (0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOID:\n      newtype = P_VOIDPTR;\n      break;\n    case P_CHAR:\n      newtype = P_CHARPTR;\n      break;\n    case P_INT:\n      newtype = P_INTPTR;\n      break;\n    case P_LONG:\n      newtype = P_LONGPTR;\n      break;\n    default:\n      fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOIDPTR:\n      newtype = P_VOID;\n      break;\n    case P_CHARPTR:\n      newtype = P_CHAR;\n      break;\n    case P_INTPTR:\n      newtype = P_INT;\n      break;\n    case P_LONGPTR:\n      newtype = P_LONG;\n      break;\n    default:\n      fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "22_Design_Locals/Readme.md",
    "content": "# Part 22: Design Ideas for Local Variables and Function Calls\n\nThis is going to be first first part of our compiler writing journey\nwhere I don't introduce any new code. This time, I need to step\nback from the coder's keyboard and take a big-picture view. This will\ngive me a chance to think about how I'm going to implement local variables\n(in one part) and then function arguments & parameters (in the next part).\n\nBoth of these steps are going to involve some significant additions and\nchanges to our existing compiler. We also have to deal with new concepts\nlike *stack frames* and *register spills*, which so far I've omitted.\n\nLet's start by identifying what new functionality we want to add to the compiler.\n\n## What Functionality Do We Want\n\n### Local and Global Variable Scopes\n\nRight now, all our variables are globally visible to all functions.\nWe want to add a\n[local scope](https://en.wikipedia.org/wiki/Scope_(computer_science))\nfor variables, so that each function has its own variables that cannot\nbe seen by other functions. Moreover, in the case of recursive functions,\neach instance of the same function gets its own local variables.\n\nHowever, I only want to add two scopes: *local* and *global*. C actually creates\na new scope for every compound statement. In the following example, there\nare three different `a` variables in three different scopes:\n\n```c\n#include <stdio.h>\nint a = 2;              // Global scope\n\nint main()\n{\n  int a= 5;             // Local scope\n  if (a > 2) {\n    int a= 17;          // Third scope\n    printf(\"%d\\n\", a);  // Print 17\n  }\n  printf(\"%d\\n\", a);    // Print 5\n  return(0);\n}\n```\n\nI'm not going to support the third, inner, scope. Two will be enough!\n\n### Function Parameters as Local Variables\n\nWe also need to support the declaration of zero or more *parameters* to\na function, and these need to be treated as variables local to the\ninstance of that function.\n\nC functions are \"[call by value](https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_value)\":\nthe argument values in the caller of a function are copied into the\nfunction's parameters so that the called function can use and modify them.\n\n### Introducing the Stack\n\nTo create a local scope for multiple instances of the same function,\nand to provide a place to store the function's parameters, we need a\n*stack*. At this point, if you don't know much about stacks,\nyou should do a bit of background reading on them. I'd start with\nthis [Wikipedia article on call stacks](https://en.wikipedia.org/wiki/Call_stack).\n\nGiven that one of the hardware architectures that we support is the\nIntel x86-64 architecture running Linux, we are going to have to implement\nthe function call mechanism on this architecture. I found this great\narticle by Eli Bendersky on the\n[stack frame layout on x86-64](https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/).\nThis is a document that you will definitely need to read before continuing\non with this document! As Eli's article is in the public domain, I'm reproducing\nhis picture of the stack frame and the parameters in registers below for\nthe function\n\n```c\nlong myfunc(long a, long b, long c, long d,\n            long e, long f, long g, long h)\n{\n    long xx, yy, zz;\n    ...\n}\n```\n\n![](Figs/x64_frame_nonleaf.png)\n\nEssentially, on the x86-64 architecture, the values of some parameters will be\npassed in registers, and some parameter values will be pushed onto the stack.\nAll our local variables will be on the stack but below the stack base pointer.\n\nAt the same time, we want our compiler to be portable to different architectures.\nSo, we will need to support a general function parameter framework for different\narchitectures which use the only the stack, only registers or a combination\nof both.\n\n### Spilling Registers\n\nSomething that I have ignored so far and not implemented yet is \n[register spilling](https://en.wikipedia.org/wiki/Register_allocation#Spilling).\nWe need to spill some or all the registers that we have allocated for\nseveral reasons:\n\n + We have run out of registers to allocate as there is only a fixed\n   number of registers. We can spill a register onto the stack so\n   that it is free to allocate.\n + We need to spill all our allocated register, and all registers with\n   parameters, onto the stack before a function call. This frees them up\n   so they can be used by the called function.\n\nOn a function call return, we will need to unspill the registers to\nget the values that we need back. Similarly, if we've spilled a register\nto make it free, then we need to unspill its old value and reallocate\nit when it becomes free again.\n\n### Static Variables\n\nWhile not on the list of things to implement immediately, at some point\nI'll need to allocate\n[static variables](https://en.wikipedia.org/wiki/Static_variable).\nThere will be some naming issues here for local static variables, but I'll\ntry to keep this in the back of my mind as I implement all of the immediate\nideas.\n\n### Initialising Variables\n\nWe should allow variables to be initialised when they are declared.\nFor global variables, we can definitely initialise them to a constant\nvalue, e.g. `int x= 7;` but not to an expression as we don't have a\n[function context](https://en.wikipedia.org/wiki/Scope_(computer_science)#Function_scope)\nto run the initialisation code in.\n\nHowever, we should be able to do\nlocal variable initialisation, e.g. `int a= 2, b= a+5;` as we can\ninsert the initialisation code for the variable at\nthe start of the function code.\n\n## Ideas and Implementation\n\nOK, so these are the ideas and issues that are bubbling around in my\ndesigner's mind at this time. Here's how I think I'm going to implement\nsome of them.\n\n### Local Symbols\n\nLet's start with the differentiation between local and global variables.\nThe globals have to be visible to all functions, but the locals are only\nvisible to one function.\n\nSubC uses the one symbol table to store information about both local and\nglobal variables. The global variables are allocated at one end and the\nlocal variables are stored at the other. There is code to ensure there is\nno collision between the two ends in the middle. I like this idea, as we then\nhave a single set of unique symbol slot numbers for every symbol, regardless\nof its scope.\n\nIn terms of prioritising local symbols over global symbols, we can\nsearch the local end of the symbol table first and, if we don't find a\nsymbol, we can then search through the global end. And, once we finish parsing\na function, we can simply wipe the local end of the symbol table.\n\n### Storage Classes\n\nC has the concept of\n[storage classes](https://en.wikipedia.org/wiki/C_syntax#Storage_class_specifiers), and we'll have to implement at least some of these classes.\nSubC implements several of the storage classes:\n\n```c\n/* storage classes */\nenum {\n        CPUBLIC = 1,            // publicly visible symbol\n        CEXTERN,                // extern symbol\n        CSTATIC,                // static symbols in global context\n        CLSTATC,                // static symbols in local context\n        CAUTO,                  // non-static local identifiers\n        CSPROTO,                // function prototype\n        CMEMBER,                // field of a struct/union\n        CSTCDEF                 // unused\n};\n```\n\nfor each symbol in the symbol table. I think I can modify and use this. But\nI'll probably support fewer storage class types.\n\n### Function Prototypes\n\nEvery function has a *prototype*: the number and type of each parameter\nthat it has. We need these to ensure the arguments to a function call matches\nthe types and number of function parameters.\n\nSomewhere I will need to record the parameter list and types for each\nfunction. We can also support the declaration of a function's prototype\nbefore the actual declaration of the function itself.\n\nNow, where are we going to store this? I could create a separate data\nstructure for function prototypes. I don't want to support two-dimensional\narrays in our language, but we will need a list of primitive types for\neach function.\n\nSo, my idea is this. We already have S_FUNCTION as the type for our\nexisting symbol table elements. We can have a \"number of parameters\" field\nin each symbol table entry to store the number of parameters that the function has.\nWe can then immediately follow this symbol with the symbol table entries\nfor each function parameter.\n\nWhen we are parsing the function's parameter list, we can add the parameters\nin the global symbol section to record the function's prototype. At the same time,\nwe can also add the parameters as entries in the local symbol section, as they\nwill be used as local variables by the function itself.\n\nWhen we need to determine if the list of arguments to a function call\nmatches the function's prototype, we can find the function's global\nsymbol table entry and then compare the following entries in the symbol\ntable to the argument list.\n\nFinally, when doing a search for a global symbol, we can easily skip past\nthe parameter entries for a function by loading the function's \"number of parameters\"\nfield and skip this many symbol table entries.\n\n### Keeping Parameters in Registers: Not Possible\n\nI'm actually writing this section after trying to implement the above, so I've come\nback to revisit the design a bit. I thought that we would be able to keep the\nparameters passed as registers in their registers: this would make access to them\nfaster and keep the stack frame smaller. But this isn't always possible for this\nreason. Consider this code:\n\n```c\nvoid myfunction(int a) {        // a is a parameter in a register\n  int b;                        // b is a local variable on the stack\n\n  // Call a function to update a and b\n  b= function2(&a);\n}\n```\n\nIf the `a` parameter is in a register, we won't be able to get its address\nwith the `&` operator. Therefore, we'll have to copy it into memory somewhere.\nAnd, given that parameters are variables local to the function, we will need to\ncopy it to the stack.\n\nFor a while I had ideas of walking the AST looking for which parameters in the\ntree needed to have real addresses, but then I remembered that I'm following the\nKISS principle: keep it simple, stupid! So I will copy all parameters out of\nregisters and onto the stack.\n\n### Location of Local Variables\n\nHow are we going to determine where a parameter or local variable is on the stack,\nonce they have been copied or placed there? To do this, I will add a `posn` field into\neach local symbol table entry. This will indicate the offset of the variable below\nthe frame base pointer.\n\nLooking at the\n[BNF Grammar for C](https://www.lysator.liu.se/c/ANSI-C-grammar-y.html),\nthe function declaration list (i.e. the list of function parameters)\ncomes before the declaration list for the local variables, and this\ncomes before the statement list.\n\nThis means that, as we parse the parameters and then the local variables, we can\ndetermine at what position they will be on the stack before we get to parse\nthe statement list.\n\n## Conclusion and What's Next\n\nI think that's about all I want to do in terms of design before I start on\nthe next parts of our compiler writing journey. I'll tackle local variables\nby themselves in the next part, and try to add in function calls and\nparameters in the following part. But it might take three or more steps\nto get all of the new proposed features implemented. We'll see. [Next step](../23_Local_Variables/Readme.md)\n"
  },
  {
    "path": "23_Local_Variables/Makefile",
    "content": "HSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c scan.c stmt.c \\\n\tsym.c tree.c types.c\n\ncomp1: $(SRCS) $(HSRCS)\n\tcc -o comp1 -g -Wall $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -o compn -g -Wall $(SRCN)\n\ncomp1arm: $(ARMSRCS) $(HSRCS)\n\tcc -o comp1arm -g -Wall $(ARMSRCS)\n\tcp comp1arm comp1\n\nclean:\n\trm -f comp1 comp1arm compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: comp1arm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "23_Local_Variables/Readme.md",
    "content": "# Part 23: Local Variables\n\nI've just implemented local variables on the stack following\nthe design ideas I described in the previous part of our\ncompiler writing journey, and it all went fine. Below, I\nwill outline the actual code changes.\n\n## Symbol Table Changes\n\nWe start with the changes to the symbol table as these\nare central to having two variable scopes: global and local.\nThe structure of the symbol table entries is now (in `defs.h`):\n\n```c\n// Storage classes\nenum {\n        C_GLOBAL = 1,           // Globally visible symbol\n        C_LOCAL                 // Locally visible symbol\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int endlabel;                 // For functions, the end label\n  int size;                     // Number of elements in the symbol\n  int posn;                     // For locals,the negative offset \n                                // from the stack base pointer\n};\n```\n\nwith the `class` and `posn` fields added. As described in the last part,\nthe `posn` is negative and holds an offset from the stack base pointer,\ni.e. the local variable is stored on the stack.\nIn this part, I've only implemented local variables, not parameters. Also\nnote that we now have symbols marked C_GLOBAL or C_LOCAL.\n\nThe symbol table's name has also changed, along with the indexed into it\n(in `data.h`):\n\n```c\nextern_ struct symtable Symtable[NSYMBOLS];     // Global symbol table\nextern_ int Globs;                              // Position of next free global symbol slot\nextern_ int Locls;                              // Position of next free local symbol slot\n```\n\nVisually, the global symbols are stored in the left-hand side of the symbol table\nwith `Globs` pointing at the next free global symbol slot and `Locls`\npointing at the next free local symbol slot.\n\n```\n0xxxx......................................xxxxxxxxxxxxNSYMBOLS-1\n     ^                                    ^\n     |                                    |\n   Globs                                Locls\n```\n\nIn `sym.c` as well as the existing `findglob()` and `newglob()` functions\nto find or allocate a global symbol, we now have `findlocl()` and `newlocl()`.\nThey have code to detect a collision between `Globs` and `Locls`:\n\n```c\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= Locls)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Get the position of a new local symbol slot, or die\n// if we've run out of positions.\nstatic int newlocl(void) {\n  int p;\n\n  if ((p = Locls--) <= Globs)\n    fatal(\"Too many local symbols\");\n  return (p);\n}\n```\n\nThere is now a generic function `updatesym()` to set all the fields in\na symbol table entry. I won't give the code because it simply sets\neach field one at a time.\n\nThe `updatesym()` function is called by `addglobl()` and `addlocl()`.\nThese first try to find an existing symbol, allocate a new one if not found,\nand call `updatesym()` to set the values for this symbol. Finally, there is\na new function, `findsymbol()`, that searches for a symbol in both local\nand global sections of the symbol table:\n\n```c\n// Determine if the symbol s is in the symbol table.\n// Return its slot position or -1 if not found.\nint findsymbol(char *s) {\n  int slot;\n\n  slot = findlocl(s);\n  if (slot == -1)\n    slot = findglob(s);\n  return (slot);\n}\n```\n\nThroughout the rest of the code, the old calls to `findglob()` have been\nreplaced with calls the `findsymbol()`.\n\n## Changes to Declaration Parsing\n\nWe need to be able to parse both global and local variable declarations.\nThe code to parse them is (for now) the same, so I added a flag to the\nfunction:\n\n```c\nvoid var_declaration(int type, int islocal) {\n    ...\n      // Add this as a known array\n      if (islocal) {\n        addlocl(Text, pointer_to(type), S_ARRAY, 0, Token.intvalue);\n      } else {\n        addglob(Text, pointer_to(type), S_ARRAY, 0, Token.intvalue);\n      }\n    ...\n    // Add this as a known scalar\n    if (islocal) {\n      addlocl(Text, type, S_VARIABLE, 0, 1);\n    } else {\n      addglob(Text, type, S_VARIABLE, 0, 1);\n    }\n    ...\n}\n```\n\nThere are two calls to `var_declaration()` in our compiler at present.\nThis one in `global_declarations()` in `decl.c` parses global variable\ndeclarations:\n\n```c\nvoid global_declarations(void) {\n      ...\n      // Parse the global variable declaration\n      var_declaration(type, 0);\n      ...\n}\n```\n\nThis one in `single_statement()` in `stmt.c` parses local variable\ndeclarations:\n\n```c\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration.\n      type = parse_type();\n      ident();\n      var_declaration(type, 1);\n   ...\n  }\n  ...\n}\n```\n\n## Changes to the x86-64 Code Generator\n\nAs always, many of the `cgXX()` functions in the platform-specific code\nin `cg.c` are exposed to the rest of the compiler as `genXX()` functions\nin `gen.c`. That's going to be the case here. So while I only mention the\n`cgXX()` functions, don't forget that there are often matching `genXX()`\nfunctions.\n\nFor each local variable, we need to allocate a position for it and\nrecord this in the symbol table's `posn` field. Here is how we do it.\nIn `cg.c` we have a new static variable and two functions to manipulate it:\n\n```c\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Reset the position of new local variables when parsing a new function\nvoid cgresetlocals(void) {\n  localOffset = 0;\n}\n\n// Get the position of the next local variable.\n// Use the isparam flag to allocate a parameter (not yet XXX).\nint cggetlocaloffset(int type, int isparam) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n```\n\nFor now, we allocate all local variables on the stack. They are aligned\nwith a minimum of 4 bytes between each one. For 64-bit integers and pointers,\nthat's 8-bytes for each variable, though.\n\n> I know, in the past, that multi-byte data items had to be properly aligned\n  in memory or the CPU would fault. It seems that, at least for x86-64,\n  there is [no need to align data items](https://lemire.me/blog/2012/05/31/data-alignment-for-speed-myth-or-reality/).\n\n> However, the stack pointer on the x86-64 *does* have to be properly aligned before\n  a function call. In \"[Optimizing Subroutines in Assembly Language](https://www.agner.org/optimize/optimizing_assembly.pdf)\" by Agner Fog, page 30, he\n  notes that \"The stack pointer must be aligned by 16 before any CALL instruction,\n  so that the value of RSP is 8 modulo 16 at the entry of a function.\"\n\n> This means that, as part of the function preamble, we need to set `%rsp` to a\n  correctly aligned value.\n\n`cgresetlocals()` is called in `function_declaration()` once we have added\nthe function's name to the symbol table but before we start parsing the\nlocal variable declarations. This sets `localOffset` back to zero.\n\nWe saw that `addlocl()` is called with a new local scalar or local array\nis parsed. `addlocl()` calls `cggetlocaloffset()` with the type of the new\nvariable. This decrements the offset from the stack base pointer by an\napproriate amount, and this offset is stored in the `posn` field for the\nsymbol.\n\nNow that we have the symbol's offset from the stack base pointer, we\nnow need to modify the code generator so that, when we are accessing a\nlocal variable instead of a global variable, we output an offset to `%rbp`\ninstead of naming a global location.\n\nThus, we now have a `cgloadlocal()` function which is nearly identical to\n`cgloadglob()` except that all `%s(%%rip)` format strings to print\n`Symtable[id].name` are replaced with `%d(%%rbp)` format strings to print\n`Symtable[id].posn`. In fact, if you search for `Symtable[id].posn` in `cg.c`,\nyou will spot all of these new local variable references.\n\n### Updating the Stack Pointer\n\nNow that we are using locations on the stack, we had better move the stack\npointer down below the area which holds our local variables. Thus, we need\nto modify the stack pointer in our function preamble and postamble:\n\n```c\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  cgtextseg();\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset= (localOffset+15) & ~15;\n  \n  fprintf(Outfile,\n          \"\\t.globl\\t%s\\n\"\n          \"\\t.type\\t%s, @function\\n\"\n          \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n          \"\\tmovq\\t%%rsp, %%rbp\\n\"\n          \"\\taddq\\t$%d,%%rsp\\n\", name, name, name, -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq %rbp\\n\" \"\\tret\\n\", Outfile);\n}\n```\n\nRemember that `localOffset` is negative. So we add a negative\nvalue in the function preamble, and add a negative negative value in the\nfunction postamble.\n\n## Testing the Changes\n\nI think that is the bulk of the changes to add local variables to our\ncompiler. The test program `tests/input25.c` demonstrates the storage of\nlocal variables on the stack:\n\n```c\nint a; int b; int c;\n\nint main()\n{\n  char z; int y; int x;\n  x= 10;  y= 20; z= 30;\n  a= 5;   b= 15; c= 25;\n}\n```\n\nHere is the annotated assembly output:\n\n```\n        .data\n        .globl  a\na:      .long   0                       # Three global variables\n        .globl  b\nb:      .long   0\n        .globl  c\nc:      .long   0\n\n        .text\n        .globl  main\n        .type   main, @function\nmain:\n        pushq   %rbp\n        movq    %rsp, %rbp\n        addq    $-16,%rsp               # Lower stack pointer by 16\n        movq    $10, %r8\n        movl    %r8d, -12(%rbp)         # z is at offset -12\n        movq    $20, %r8\n        movl    %r8d, -8(%rbp)          # y is at offset -8\n        movq    $30, %r8\n        movb    %r8b, -4(%rbp)          # x is at offfset -4\n        movq    $5, %r8\n        movl    %r8d, a(%rip)           # a has a global label\n        movq    $15, %r8\n        movl    %r8d, b(%rip)           # b has a global label\n        movq    $25, %r8\n        movl    %r8d, c(%rip)           # c has a global label\n        jmp     L1\nL1:\n        addq    $16,%rsp                # Raise stack pointer by 16\n        popq    %rbp\n        ret\n```\n\nFinally, a `$ make test` demonstrates that the compiler passes all\nprevious tests.\n\n## Conclusion and What's Next\n\nI thought implementing local variables was going to be tricky, but after\ndoing some thinking about the design of a solution, it turned out to be\neasier than I expected. Somehow I suspect the next step will be the tricky one.\n\nIn the next part of our compiler writing journey, I will attempt to\nadd function arguments and parameters to our compiler. Wish me luck! [Next step](../24_Function_Params/Readme.md)\n"
  },
  {
    "path": "23_Local_Variables/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Reset the position of new local variables when parsing a new function\nvoid cgresetlocals(void) {\n  localOffset = 0;\n}\n\n// Get the position of the next local variable.\n// Use the isparam flag to allocate a parameter (not yet XXX).\nint cggetlocaloffset(int type, int isparam) {\n  // For now just decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n// printf(\"Returning offset %d for type %d\\n\", localOffset, type);\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n#define NUMFREEREGS 4\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] = { \"%r8\", \"%r9\", \"%r10\", \"%r11\" };\nstatic char *breglist[] = { \"%r8b\", \"%r9b\", \"%r10b\", \"%r11b\" };\nstatic char *dreglist[] = { \"%r8d\", \"%r9d\", \"%r10d\", \"%r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  cgtextseg();\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset= (localOffset+15) & ~15;\n  // printf(\"preamble local %d stack %d\\n\", localOffset, stackOffset);\n  \n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\"\n\t  \"\\taddq\\t$%d,%%rsp\\n\", name, name, name, -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", id, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r],\n\t      Symtable[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r],\n\t      Symtable[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r],\n\t      Symtable[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r],\n\t      Symtable[id].posn);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r],\n\t      Symtable[id].posn);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r],\n\t      Symtable[id].posn);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch (typesize) {\n      case 1:\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"\\t.long\\t0\\n\");\n\tbreak;\n      case 8:\n\tfprintf(Outfile, \"\\t.quad\\t0\\n\");\n\tbreak;\n      default:\n\tfatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_LOCAL)\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "23_Local_Variables/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4, 4, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "23_Local_Variables/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Reset the position of new local variables when parsing a new function\nvoid cgresetlocals(void) {\n  localOffset = 0;\n}\n\n// Get the position of the next local variable.\n// Use the isparam flag to allocate a parameter (not yet XXX).\nint cggetlocaloffset(int type, int isparam) {\n  // For now just decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n// printf(\"Returning offset %d for type %d\\n\", localOffset, type);\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n#define NUMFREEREGS 4\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r8\",  \"r9\",  \"r10\",  \"r11\" };\nstatic char *breglist[] = { \"r8b\", \"r9b\", \"r10b\", \"r11b\" };\nstatic char *dreglist[] = { \"r8d\", \"r9d\", \"r10d\", \"r11d\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  cgtextseg();\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset= (localOffset+15) & ~15;\n  // printf(\"preamble local %d stack %d\\n\", localOffset, stackOffset);\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\"\n          \"\\tadd\\trsp, %d\\n\", name, name, -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Symtable[id].name);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              Symtable[id].name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Symtable[id].name);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              Symtable[id].posn);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n              Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n              Symtable[id].posn);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], id);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  // original version\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch(typesize) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(typesize) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", Symtable[id].size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", Symtable[id].size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", Symtable[id].size);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_LOCAL)\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            Symtable[id].posn);\n  else\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Symtable[id].name);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "23_Local_Variables/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ int Locls;\t\t// Position of next free local symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Symtable[NSYMBOLS];\t// Global symbol table\n\nextern_ int O_dumpAST;\n"
  },
  {
    "path": "23_Local_Variables/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      break;\n    case T_INT:\n      type = P_INT;\n      break;\n    case T_LONG:\n      type = P_LONG;\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type\nvoid var_declaration(int type, int islocal) {\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      if (islocal) {\n\taddlocl(Text, pointer_to(type), S_ARRAY, 0, Token.intvalue);\n      } else {\n\taddglob(Text, pointer_to(type), S_ARRAY, 0, Token.intvalue);\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    if (islocal) {\n      addlocl(Text, type, S_VARIABLE, 0, 1);\n    } else {\n      addglob(Text, type, S_VARIABLE, 0, 1);\n    }\n  }\n\n  // Get the trailing semicolon\n  semi();\n}\n\n//\n// function_declaration: type identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function.\n// The identifier has been scanned & we have the type\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int nameslot, endlabel;\n\n  // Text now has the identifier's name.\n  // Get a label-id for the end label, add the function\n  // to the symbol table, and set the Functionid global\n  // to the function's symbol-id\n  endlabel = genlabel();\n  nameslot = addglob(Text, type, S_FUNCTION, endlabel, 0);\n  Functionid = nameslot;\n\n  genresetlocals();\t\t// Reset position of new locals\n\n  // Scan in the parentheses\n  lparen();\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, nameslot));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration and\n      // generate the assembly code for it\n      tree = function_declaration(type);\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n    } else {\n\n      // Parse the global variable declaration\n      var_declaration(type, 0);\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "23_Local_Variables/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(int id);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\nvoid genresetlocals(void);\nint gengetlocaloffset(int type, int isparam);\n\n// cg.c\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id, int op);\nint cgloadlocal(int id, int op);\nint cgloadglobstr(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(int r, int id);\nint cgstorglob(int r, int id);\nint cgstorlocal(int r, int id);\nvoid cgglobsym(int id);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgresetlocals(void);\nint cggetlocaloffset(int type, int isparam);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint findlocl(char *s);\nint findsymbol(char *s);\nint addglob(char *name, int type, int stype, int endlabel, int size);\nint addlocl(char *name, int type, int stype, int endlabel, int size);\n\n// decl.c\nvoid var_declaration(int type, int islocal);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint parse_type(void);\nint pointer_to(int type);\nint value_at(int type);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "23_Local_Variables/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND, \n  T_OR, T_XOR, T_AMPER, \n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN= 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n#define NOLABEL\t 0\t\t// Use NOLABEL when we have no label to\n\t\t\t\t// pass to genAST()\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n        C_GLOBAL = 1,\t\t// Globally visible symbol\n        C_LOCAL\t\t\t// Locally visible symbol\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int endlabel;\t\t\t// For functions, the end label\n  int size;\t\t\t// Number of elements in the symbol\n  int posn;\t\t\t// For locals,the negative offset\n\t\t\t\t// from the stack base pointer\n};\n"
  },
  {
    "path": "23_Local_Variables/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a function call with a single expression\n// argument and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Symtable[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and\n// return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  int id;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, Symtable[id].type, id);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, Symtable[id].type, left, NULL, right, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  int id;\n\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // A variable. Check that the variable exists.\n  id = findsymbol(Text);\n  if (id == -1 || Symtable[id].stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n      // Post-increment: skip over the token\n    case T_INC:\n      scan(&Token);\n      n = mkastleaf(A_POSTINC, Symtable[id].type, id);\n      break;\n\n      // Post-decrement: skip over the token\n    case T_DEC:\n      scan(&Token);\n      n = mkastleaf(A_POSTDEC, Symtable[id].type, id);\n      break;\n\n      // Just a variable reference\n    default:\n      n = mkastleaf(A_IDENT, Symtable[id].type, id);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n\tn = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n      break;\n\n    case T_STRLIT:\n      // For a STRLIT token, generate the assembly for it.\n      // Then make a leaf AST node for it. id is the string's label.\n      id = genglobstr(Text);\n      n = mkastleaf(A_STRLIT, P_CHARPTR, id);\n      break;\n\n    case T_IDENT:\n      return (postfix());\n\n    case T_LPAREN:\n      // Beginning of a parenthesised expression, skip the '('.\n      // Scan in the expression and the right parenthesis\n      scan(&Token);\n      n = binexpr(0);\n      rparen();\n      return (n);\n\n    default:\n      fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n    case T_AMPER:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Ensure that it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"& operator must be followed by an identifier\");\n\n      // Now change the operator to A_ADDR and the type to\n      // a pointer to the original type\n      tree->op = A_ADDR;\n      tree->type = pointer_to(tree->type);\n      break;\n    case T_STAR:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's either another deref or an\n      // identifier\n      if (tree->op != A_IDENT && tree->op != A_DEREF)\n\tfatal(\"* operator must be followed by an identifier or *\");\n\n      // Prepend an A_DEREF operation to the tree\n      tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n      break;\n    case T_MINUS:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_NEGATE operation to the tree and\n      // make the child an rvalue. Because chars are unsigned,\n      // also widen this to int so that it's signed\n      tree->rvalue = 1;\n      tree = modify_type(tree, P_INT, 0);\n      tree = mkastunary(A_NEGATE, tree->type, tree, 0);\n      break;\n    case T_INVERT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_INVERT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_INVERT, tree->type, tree, 0);\n      break;\n    case T_LOGNOT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_LOGNOT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_LOGNOT, tree->type, tree, 0);\n      break;\n    case T_INC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"++ operator must be followed by an identifier\");\n\n      // Prepend an A_PREINC operation to the tree\n      tree = mkastunary(A_PREINC, tree->type, tree, 0);\n      break;\n    case T_DEC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"-- operator must be followed by an identifier\");\n\n      // Prepend an A_PREDEC operation to the tree\n      tree = mkastunary(A_PREDEC, tree->type, tree, 0);\n      break;\n    default:\n      tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN || tokentype == T_RBRACKET) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (left == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(binastop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon, ')' or ']', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN\n\t|| tokentype == T_RBRACKET) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "23_Local_Variables/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOLABEL, n->op);\n      genfreeregs();\n      genAST(n->right, NOLABEL, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->v.id);\n      genAST(n->left, NOLABEL, n->op);\n      cgfuncpostamble(n->v.id);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->v.id));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (Symtable[n->v.id].class == C_LOCAL) {\n\t  return (cgloadlocal(n->v.id, n->op));\n\t} else {\n\t  return (cgloadglob(n->v.id, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (Symtable[n->right->v.id].class == C_LOCAL)\n\t    return (cgstorlocal(leftreg, n->right->v.id));\n\t  else\n\t    return (cgstorglob(leftreg, n->right->v.id));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_FUNCCALL:\n      return (cgcall(leftreg, n->v.id));\n    case A_ADDR:\n      return (cgaddress(n->v.id));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->v.size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->v.size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n      // Load the variable's value into a register,\n      // then increment it\n      return (cgloadglob(n->v.id, n->op));\n    case A_POSTDEC:\n      // Load the variable's value into a register,\n      // then decrement it\n      return (cgloadglob(n->v.id, n->op));\n    case A_PREINC:\n      // Load and increment the variable's value into a register\n      return (cgloadglob(n->left->v.id, n->op));\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      return (cgloadglob(n->left->v.id, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, label));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nvoid genresetlocals(void) {\n  cgresetlocals();\n}\nint gengetlocaloffset(int type, int isparam) {\n  return (cggetlocaloffset(type, isparam));\n}\n"
  },
  {
    "path": "23_Local_Variables/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n\nvoid printchar(long x) {\n  putc((char)(x & 0x7f), stdout);\n}\n"
  },
  {
    "path": "23_Local_Variables/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n  Globs = 0;\n  Locls = NSYMBOLS - 1;\n  O_dumpAST = 0;\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-T] infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nint main(int argc, char *argv[]) {\n  int i;\n\n  // Initialise the globals\n  init();\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    if (*argv[i] != '-')\n      break;\n    for (int j = 1; argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have an input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Open up the input file\n  if ((Infile = fopen(argv[i], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[i], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n  // For now, ensure that printint() and printchar() are defined\n  addglob(\"printint\", P_INT, S_FUNCTION, 0, 0);\n  addglob(\"printchar\", P_VOID, S_FUNCTION, 0, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  return (0);\n}\n"
  },
  {
    "path": "23_Local_Variables/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "23_Local_Variables/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "23_Local_Variables/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Symtable[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Symtable[Functionid].type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration.\n      type = parse_type();\n      ident();\n      var_declaration(type, 1);\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "23_Local_Variables/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= Locls)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return its slot position or -1 if not found.\nint findlocl(char *s) {\n  int i;\n\n  for (i = Locls + 1; i < NSYMBOLS; i++) {\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new local symbol slot, or die\n// if we've run out of positions.\nstatic int newlocl(void) {\n  int p;\n\n  if ((p = Locls--) <= Globs)\n    fatal(\"Too many local symbols\");\n  return (p);\n}\n\n// Update a symbol at the given slot number in the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + endlabel: if this is a function\n// + posn: Position information for local symbols\nstatic void updatesym(int slot, char *name, int type, int stype,\n\t\t      int class, int endlabel, int size, int posn) {\n  if (slot < 0 || slot >= NSYMBOLS)\n    fatal(\"Invalid symbol slot number in updatesym()\");\n  Symtable[slot].name = strdup(name);\n  Symtable[slot].type = type;\n  Symtable[slot].stype = stype;\n  Symtable[slot].class = class;\n  Symtable[slot].endlabel = endlabel;\n  Symtable[slot].size = size;\n  Symtable[slot].posn = posn;\n}\n\n// Add a global symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + endlabel: if this is a function\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int endlabel, int size) {\n  int slot;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((slot = findglob(name)) != -1)\n    return (slot);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  slot = newglob();\n  updatesym(slot, name, type, stype, C_GLOBAL, endlabel, size, 0);\n  genglobsym(slot);\n  return (slot);\n}\n\n// Add a local symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + endlabel: if this is a function\n// Return the slot number in the symbol table\nint addlocl(char *name, int type, int stype, int endlabel, int size) {\n  int slot, posn;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((slot = findlocl(name)) != -1)\n    return (slot);\n\n  // Otherwise get a new symbol slot and a position for this local.\n  // Update the symbol table entry and return the slot number\n  slot = newlocl();\n  posn = gengetlocaloffset(type, 0);\t// XXX 0 for now\n  updatesym(slot, name, type, stype, C_LOCAL, endlabel, size, posn);\n  return (slot);\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return its slot position or -1 if not found.\nint findsymbol(char *s) {\n  int slot;\n\n  slot = findlocl(s);\n  if (slot == -1)\n    slot = findglob(s);\n  return (slot);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input01.c",
    "content": "void main()\n{ printint(12 * 3);\n  printint(18 - 2 * 4);\n  printint(1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input02.c",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printint(fred + jim);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input03.c",
    "content": "void main()\n{\n  int x;\n  x= 1;     printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input04.c",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  printint(x);\n  x= 7 <= 9; printint(x);\n  x= 7 != 9; printint(x);\n  x= 7 == 7; printint(x);\n  x= 7 >= 7; printint(x);\n  x= 7 <= 7; printint(x);\n  x= 9 > 7;  printint(x);\n  x= 9 >= 7; printint(x);\n  x= 9 != 7; printint(x);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input05.c",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printint(i);\n  } else {\n    printint(j);\n  }\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input06.c",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printint(i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input07.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input08.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input09.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printint(2 * b - a); }\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input10.c",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; printint(j);\n  i= 10; printint(i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 2; j= j + 1) { printint(j); }\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input11.c",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; printint(i);\n  j= 20; printint(j);\n  k= 30; printint(k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 4; j= j + 1) { printint(j); }\n  for (k= 1;   k <= 5; k= k + 1) { printint(k); }\n  return(i);\n  printint(12345);\n  return(3);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input12.c",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printint(x);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input13.c",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input14.c",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input15.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printint(a);\n  b= &a; c= *b; printint(c);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input16.c",
    "content": "int   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printint(c);\n  e= &c + 1; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input17.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printint(a);\n  e= &d; *e= 12; printint(d);\n  return(0);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input18.c",
    "content": "int main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printint(a);\n  printint(b);\n  return(0);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input18a.c",
    "content": "int   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printint(a);\n  d= &c; *d= 16; printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input19.c",
    "content": "int a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printint(e);\n  return(0);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input20.c",
    "content": "int a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printint(a);\n  return(0);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input21.c",
    "content": "char  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printint(c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printchar(*str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input22.c",
    "content": "char a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printint(a);\n  e= 5; f= 7; d= e + f++; printint(d);\n  h= 5; i= 7; g= h + i++; printint(g);\n  a= b-- + c; printint(a);\n  d= e-- + f; printint(d);\n  g= h-- + i; printint(g);\n  a= ++b + c; printint(a);\n  d= ++e + f; printint(d);\n  g= ++h + i; printint(g);\n  a= b * --c; printint(a);\n  d= e * --f; printint(d);\n  g= h * --i; printint(g);\n  return(0);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input23.c",
    "content": "char *str;\nint   x;\n\nint main() {\n  x= -23; printint(x);\n  printint(-10 * -10);\n\n  x= 1; x= ~x; printint(x);\n\n  x= 2 > 5; printint(x);\n  x= !x; printint(x);\n  x= !x; printint(x);\n\n  x= 13; if (x) { printint(13); }\n  x= 0; if (!x) { printint(14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printchar(*str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input24.c",
    "content": "int a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printint(a & b);\n  printint(a | b);\n  printint(a ^ b);\n  printint(1 << 3);\n  printint(63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/input25.c",
    "content": "int a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printint(x); printint(y); printint(z);\n  a= 5; b= 15; c= 25;\n  printint(a); printint(b); printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "23_Local_Variables/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" ]\n   then\n     cc -o out $i ../lib/printint.c\n     ./out > out.$i\n     rm -f out\n   fi\ndone\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "23_Local_Variables/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "23_Local_Variables/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "23_Local_Variables/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -Wall -o out out.o ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "23_Local_Variables/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->v.intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->v.id);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", Symtable[n->v.id].name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->v.size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "23_Local_Variables/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  if (type == P_CHAR || type == P_INT || type == P_LONG)\n    return (1);\n  return (0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  if (type == P_VOIDPTR || type == P_CHARPTR ||\n      type == P_INTPTR || type == P_LONGPTR)\n    return (1);\n  return (0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOID:\n      newtype = P_VOIDPTR;\n      break;\n    case P_CHAR:\n      newtype = P_CHARPTR;\n      break;\n    case P_INT:\n      newtype = P_INTPTR;\n      break;\n    case P_LONG:\n      newtype = P_LONGPTR;\n      break;\n    default:\n      fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOIDPTR:\n      newtype = P_VOID;\n      break;\n    case P_CHARPTR:\n      newtype = P_CHAR;\n      break;\n    case P_INTPTR:\n      newtype = P_INT;\n      break;\n    case P_LONGPTR:\n      newtype = P_LONG;\n      break;\n    default:\n      fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "24_Function_Params/Makefile",
    "content": "HSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncomp1: $(SRCS) $(HSRCS)\n\tcc -o comp1 -g -Wall $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -o compn -g -Wall $(SRCN)\n\ncomp1arm: $(ARMSRCS) $(HSRCS)\n\tcc -o comp1arm -g -Wall $(ARMSRCS)\n\tcp comp1arm comp1\n\nclean:\n\trm -f comp1 comp1arm compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: comp1arm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\ntest27: comp1 input27a.c input27b.c\n\t./comp1 input27a.c\n\tcc -o out input27b.c out.s lib/printint.c \n\t./out\n\ntest27n: compn input27a.c input27b.c\n\t./compn input27a.c\n\tnasm -f elf64 out.s\n\tcc -o out input27b.c out.o lib/printint.c \n\t./out\n"
  },
  {
    "path": "24_Function_Params/Readme.md",
    "content": "# Part 24: Function Parameters \n\nI've just implemented the copying of function parameters out of the\nregisters and onto the function's stack, but I haven't yet implemented\nthe calling of a function with arguments.\n\nAs a recap, here is the image from Eli Bendersky's article on the\n[stack frame layout on x86-64](https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/).\n\n![](../22_Design_Locals/Figs/x64_frame_nonleaf.png)\n\nUp to six \"call by value\" arguments to a function are passed in via the\nregisters '%rdi' to '%r9'. For more than six arguments, the remaining arguments\nare pushed on the stack.\n\nWhen the function is called, it pushes the previous stack base pointer\nonto the stack, moves the stack base pointer down to point at the same\nlocation as the stack pointer, and then moves the stack pointer to\nthe lowest local variable (at minimum).\n\nWhy \"at minimum\"? Well, \nwe also have to lower the stack pointer down to be a multiple of sixteen,\nso that the stack base pointer is aligned correctly before we call\nanother function.\n\nThe arguments which were pushed on the stack are going to remain there,\nwith an offset from the stack base pointer which is positive. All the\nregister-passed arguments we will copy onto the stack, and also set up\nlocations on the stack for our local variables. These will have\noffsets from the stack base pointer which are negative.\n\nThis is the goal, but we have to get a few things done first.\n\n## New Tokens and Scanning\n\nTo start with, function declarations in ANSI C are a comma-separated\nlist of types and variable names, e.g.\n\n```c\nint function(int x, char y, long z) { ... }\n```\n\nThus, we need a new token, T_COMMA, and a change to the lexical scanner\nto read it in. I'll leave you to read the changes to `scan()` in `scan.c`.\n\n## A New Storage Class\n\nIn the last part of our compiler writing journey, I described the changes\nto the symbol table to support both global and local variables. We store\nglobals at one end of the table, and locals at the other end. Now, I'm\ngoing to introduce function parameters.\n\nI've added a new storage class definition in `defs.h`:\n\n```c\n// Storage classes\nenum {\n        C_GLOBAL = 1,           // Globally visible symbol\n        C_LOCAL,                // Locally visible symbol\n        C_PARAM                 // Locally visible function parameter\n};\n```\n\nWhere will they appear in the symbol table? Actually, the same parameter\nwill appear in both the global and the local end of the table.\n\nIn the global symbol list, we will define the function's symbol first with\nan C_GLOBAL, S_FUNCTION entry. Then, we will define all the parameters with\nconsecutive entries that are marked as C_PARAM. This is the function's\n*prototype*. It means that, when we call the function later, we can\ncompare the argument list to the parameter list and ensure that they match.\n\nAt the same time, the same list of parameters are stored in the local\nsymbol list, marked as C_PARAM instead of C_LOCAL. This allows us to\ndistinguish between the variables someone else sent to us, and the\nvariables we declared ourselves.\n\n## Changes to the Parser\n\nIn this part of the journey, I'm only dealing with function declarations.\nWe will need to modify the parser to do this. Once we have parsed the\nfunction's type, name and the opening '(', we can look for any parameters.\nEach parameter is declared following the normal variable declaration\nsyntax, but instead of ending with a semicolon, the parameter declarations are\nseparated from commas.\n\nThe old `var_declaration()` function in `decl.c` used to scan in the T_SEMI\ntoken at the end of a variable declaration. This has now been moved out to\nthe previous callers of `var_declaration()`.\n\nWe now have a new function, `param_declaration()` whose job is to read the\nlist of (zero or more) parameters that follow after the opening parenthesis:\n\n```c\n// param_declaration: <null>\n//           | variable_declaration\n//           | variable_declaration ',' param_declaration\n//\n// Parse the parameters in parentheses after the function name.\n// Add them as symbols to the symbol table and return the number\n// of parameters.\nstatic int param_declaration(void) {\n  int type;\n  int paramcnt=0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n    // Get the type and identifier\n    // and add it to the symbol table\n    type = parse_type();\n    ident();\n    var_declaration(type, 1, 1);\n    paramcnt++;\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n      case T_COMMA: scan(&Token); break;\n      case T_RPAREN: break;\n      default:\n        fatald(\"Unexpected token in parameter list\", Token.token);\n    }\n  }\n\n  // Return the count of parameters\n  return(paramcnt);\n}\n```\n\nThe two '1' arguments to `var_declaration()` indicate that this is a local\nvariable and also a parameter declaration. And in `var_declaration()`, we\nnow do:\n\n```c\n    // Add this as a known scalar\n    // and generate its space in assembly\n    if (islocal) {\n      if (addlocl(Text, type, S_VARIABLE, isparam, 1)==-1)\n       fatals(\"Duplicate local variable declaration\", Text);\n    } else {\n      addglob(Text, type, S_VARIABLE, 0, 1);\n    }\n```\n\nThe code used to allow duplicate local variable declarations, but this is\nnow going to cause the stack to grow more than is needed, so I've made\nany duplicate declaration a fatal error.\n\n## Symbol Table Changes\n\nEarlier on, I said that a parameter would be placed in both the global\nand local ends of the symbol table, but the above code only shows a\ncall to `addlocl()`. So what's going on, then?\n\nI've modified `addlocal()` to also add a parameter to the global end:\n\n```c\nint addlocl(char *name, int type, int stype, int isparam, int size) {\n  int localslot, globalslot;\n  ...\n  localslot = newlocl();\n  if (isparam) {\n    updatesym(localslot, name, type, stype, C_PARAM, 0, size, 0);\n    globalslot = newglob();\n    updatesym(globalslot, name, type, stype, C_PARAM, 0, size, 0);\n  } else {\n    updatesym(localslot, name, type, stype, C_LOCAL, 0, size, 0);\n  }\n```\n\nNot only do we get a local slot in the symbol table for a parameter,\nwe also get a global slot for it. And both are marked as C_PARAM,\nnot C_LOCAL.\n\nGiven that the global end now contains symbols which are not C_GLOBAL,\nwe need to modify the code to search for global symbols:\n\n```c\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\n// Skip C_PARAM entries\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (Symtable[i].class == C_PARAM) continue;\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n```\n\n## x86-64 Code Generator Changes\n\nThat's about it for parsing function parameters and recording their\nexistence in the symbol table. Now we need to generate a suitable\nfunction preamble that copies in-register arguments into positions\non the stack as well as setting up the new stack base pointer and\nstack pointer.\n\nI realised, after I'd written the `cgresetlocals()` in the last part,\nthan I can reset the stack offset when I call `cgfuncpreamble()`, so\nI've removed this function. Also, the code to calculate an offset for\na new local variable only needs to be visible in `cg.c`, so I've\nrenamed it:\n\n```c\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n```\n\nI've also switched from calculating a negative offset to calculating a\npositive offset, as this makes the maths (in my head) easier. I still\nreturn a negative offset as shown by the return value.\n\nWe have six new register that are going to hold argument values, so we\nhad better name them somewhere. I've extended the list of register names\nthus:\n\n```c\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9         // Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n\"%rdi\" };\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n\"%dil\" };\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n\"%esi\", \"%edi\" };\n```\n\nFIRSTPARAMREG is actually the last entry position in each list. We will \nstart at this end and work backwards.\n\nNow we turn our attention to the function that's going to do all the work\nfor us, `cgfuncpreamble()`. Let's look at the code in stages:\n\n```c\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  int i;\n  int paramOffset = 16;         // Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG; // Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset= 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n          \"\\t.globl\\t%s\\n\"\n          \"\\t.type\\t%s, @function\\n\"\n          \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n          \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n```\n\nFirst up, declare the function, save the old base pointer and move it\ndown to where the current stack pointer is. We also know that any\non-stack arguments will be 16 above the new base pointer, and we know\nwhich will be the register with the first parameter in it.\n\n```c\n  // Copy any in-register parameters to the stack\n  // Stop after no more than six parameter registers\n  for (i = NSYMBOLS - 1; i > Locls; i--) {\n    if (Symtable[i].class != C_PARAM)\n      break;\n    if (i < NSYMBOLS - 6)\n      break;\n    Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    cgstorlocal(paramReg--, i);\n  }\n```\n\nThis loops up to six times, but leaves the loop once we hit something\nthat isn't a C_PARAM, i.e. a C_LOCAL. Call `newlocaloffset()` to\ngenerate an offset from the base pointer on the stack, and copy\nthe register argument to this location on the stack.\n\n```c\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (; i > Locls; i--) {\n    if (Symtable[i].class == C_PARAM) {\n      Symtable[i].posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    }\n  }\n```\n\nFor each remaining local variable: if it's a C_PARAM, then it is already on\nthe stack, so simply record its existing position in the symbol table. If\nit's a C_LOCAL, create a new position on the stack and record it.\nWe now have our new stack frame set up with all the local variables that\nwe need. All that is left is to align the stack pointer on a multiple of\nsixteen:\n\n```c\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n```\n\n`stackOffset` is a static variable visible throughout `cg.c`. We need to\nremember this value as, at the function's postamble, we need to increase\nthe stack value by the amount that we lowered it, as well as restore the old\nstack base pointer:\n\n```c\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq %rbp\\n\" \"\\tret\\n\", Outfile);\n}\n```\n\n## Testing the Changes\n\nWith these changes to the compiler, we can declare a function with\nmany parameters as well as whatever local variables we need. But\nthe compiler doesn't yet generate code to pass arguments in registers etc.\n\nSo, to test this change to our compiler, we write some functions with\nparameters and compile them with our compiler (`input27a.c`):\n\n```c\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printint(a); printint(b); printint(c); printint(d);\n  printint(e); printint(f); printint(g); printint(h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n```\n\nAnd we write a separate file, `input27b.c`, and compile this with `gcc`:\n\n```c\n#include <stdio.h>\nextern int param8(int a, int b, int c, int d, int e, int f, int g, int h);\nextern int param5(int a, int b, int c, int d, int e);\nextern int param2(int a, int b);\nextern int param0();\n\nint main() {\n  param8(1,2,3,4,5,6,7,8); puts(\"--\");\n  param5(1,2,3,4,5); puts(\"--\");\n  param2(1,2); puts(\"--\");\n  param0();\n  return(0);\n}\n```\n\nThen we can link them together and see if the executable runs:\n\n```\ncc -o comp1 -g -Wall cg.c decl.c expr.c gen.c main.c misc.c\n      scan.c stmt.c sym.c tree.c types.c\n./comp1 input27a.c\ncc -o out input27b.c out.s lib/printint.c \n./out\n1\n2\n3\n4\n5\n6\n7\n8\n--\n1\n2\n3\n4\n5\n--\n1\n2\n3\n4\n5\n--\n1\n2\n3\n4\n5\n```\n\nAnd it works! I put an exclamation mark in because it still feels like\nmagic sometimes when things work. Let's examine the assembly code for\n`param8()`:\n\n```\nparam8:\n        pushq   %rbp                    # Save %rbp, move %rsp\n        movq    %rsp, %rbp\n        movl    %edi, -4(%rbp)          # Copy six arguments into locals\n        movl    %esi, -8(%rbp)          # on the stack\n        movl    %edx, -12(%rbp)\n        movl    %ecx, -16(%rbp)\n        movl    %r8d, -20(%rbp)\n        movl    %r9d, -24(%rbp)\n        addq    $-32,%rsp               # Lower stack pointer by 32\n        movslq  -4(%rbp), %r10\n        movq    %r10, %rdi\n        call    printint                # Print -4(%rbp), i.e. a\n        movq    %rax, %r11\n        movslq  -8(%rbp), %r10\n        movq    %r10, %rdi\n        call    printint                # Print -8(%rbp), i.e. b\n        movq    %rax, %r11\n        movslq  -12(%rbp), %r10\n        movq    %r10, %rdi\n        call    printint                # Print -12(%rbp), i.e. c\n        movq    %rax, %r11\n        movslq  -16(%rbp), %r10\n        movq    %r10, %rdi\n        call    printint                # Print -16(%rbp), i.e. d\n        movq    %rax, %r11\n        movslq  -20(%rbp), %r10\n        movq    %r10, %rdi\n        call    printint                # Print -20(%rbp), i.e. e\n        movq    %rax, %r11\n        movslq  -24(%rbp), %r10\n        movq    %r10, %rdi\n        call    printint                # Print -24(%rbp), i.e. f\n        movq    %rax, %r11\n        movslq  16(%rbp), %r10\n        movq    %r10, %rdi\n        call    printint                # Print 16(%rbp), i.e. g\n        movq    %rax, %r11\n        movslq  24(%rbp), %r10\n        movq    %r10, %rdi\n        call    printint                # Print 24(%rbp), i.e. h\n        movq    %rax, %r11\n        movq    $0, %r10\n        movl    %r10d, %eax\n        jmp     L1\nL1:\n        addq    $32,%rsp                # Raise stack pointer by 32\n        popq    %rbp                    # Restore %rbp and return\n        ret\n```\n\nSome of the other functions in `input27a.c` have both parameter variables\nand locally declared variables, so it seems the preamble being generated\nis correct (OK, works well enough to pass these tests!).\n\n## Conclusion and What's Next\n\nI took a couple of attempts to get this right. The first time I walked\nthe local symbol list in the wrong direction and got the order of\nparameters incorrect. And I misread the image from Eli Bendersky's article\nwhich resulted in my preamble tromping on the old base pointer. In a way,\nthis was good because the rewritten code is a lot cleaner than the original\ncode.\n\nIn the next part of our compiler writing journey, I'll modify the compiler\nto make function calls with an arbirary number of arguments. Then I can\nmove `input27a.c` and `input27b.c` into the `tests/` directory. [Next step](../25_Function_Arguments/Readme.md)\n"
  },
  {
    "path": "24_Function_Params/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n\"%rdi\" };\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n\"%dil\" };\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n\"%esi\", \"%edi\" };\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  int i;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset= 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack\n  // Stop after no more than six parameter registers\n  for (i = NSYMBOLS - 1; i > Locls; i--) {\n    if (Symtable[i].class != C_PARAM)\n      break;\n    if (i < NSYMBOLS - 6)\n      break;\n    Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    cgstorlocal(paramReg--, i);\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (; i > Locls; i--) {\n    if (Symtable[i].class == C_PARAM) {\n      Symtable[i].posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    }\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n    break;\n  case P_INT:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    break;\n  case P_INT:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    break;\n  default:\n    fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", id, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rdi\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r],\n\t    Symtable[id].name);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r],\n\t    Symtable[id].name);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r],\n\t    Symtable[id].name);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r],\n\t    Symtable[id].posn);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r],\n\t    Symtable[id].posn);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r],\n\t    Symtable[id].posn);\n    break;\n  default:\n    fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n    break;\n  case P_LONG:\n    fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n    break;\n  default:\n    fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_LOCAL)\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n    fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  default:\n    fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  case P_LONG:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "24_Function_Params/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4, 4, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "24_Function_Params/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  int i;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack\n  // Stop after no more than six parameter registers\n  for (i = NSYMBOLS - 1; i > Locls; i--) {\n    if (Symtable[i].class != C_PARAM)\n      break;\n    if (i < NSYMBOLS - 6)\n      break;\n    Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    cgstorlocal(paramReg--, i);\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (; i > Locls; i--) {\n    if (Symtable[i].class == C_PARAM) {\n      Symtable[i].posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    }\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n            Symtable[id].name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n    break;\n  case P_INT:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n            Symtable[id].name);\n    fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Symtable[id].name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n            Symtable[id].posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n    break;\n  case P_INT:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n            Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n    if (op == A_POSTINC)\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            Symtable[id].posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n    break;\n  default:\n    fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], id);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  // Get a new register\n  int outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\trdi, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  free_register(r);\n  return (outr);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, breglist[r]);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, dreglist[r]);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n            breglist[r]);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n            dreglist[r]);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n            reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  // original version\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch(typesize) {\n    case 1:\n      fprintf(Outfile, \"\\tdb\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tdd\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tdq\\t0\\n\");\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(typesize) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", Symtable[id].size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", Symtable[id].size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", Symtable[id].size);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n    break;\n  case P_LONG:\n    fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n    break;\n  default:\n    fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_LOCAL)\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            Symtable[id].posn);\n  else\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Symtable[id].name);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n    fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  default:\n    fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n    break;\n  case P_LONG:\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "24_Function_Params/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ int Locls;\t\t// Position of next free local symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Symtable[NSYMBOLS];\t// Global symbol table\n\nextern_ int O_dumpAST;\n"
  },
  {
    "path": "24_Function_Params/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      break;\n    case T_INT:\n      type = P_INT;\n      break;\n    case T_LONG:\n      type = P_LONG;\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type\n// islocal is set if this is a local variable\n// isparam is set if this local variable is a function parameter\nvoid var_declaration(int type, int islocal, int isparam) {\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      if (islocal) {\n\tfatal(\"For now, declaration of local arrays is not implemented\");\n      } else {\n\taddglob(Text, pointer_to(type), S_ARRAY, 0, Token.intvalue);\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    if (islocal) {\n      if (addlocl(Text, type, S_VARIABLE, isparam, 1)==-1)\n       fatals(\"Duplicate local variable declaration\", Text);\n    } else {\n      addglob(Text, type, S_VARIABLE, 0, 1);\n    }\n  }\n}\n\n// param_declaration: <null>\n//           | variable_declaration\n//           | variable_declaration ',' param_declaration\n//\n// Parse the parameters in parentheses after the function name.\n// Add them as symbols to the symbol table and return the number\n// of parameters.\nstatic int param_declaration(void) {\n  int type;\n  int paramcnt=0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n    // Get the type and identifier\n    // and add it to the symbol table\n    type = parse_type();\n    ident();\n    var_declaration(type, 1, 1);\n    paramcnt++;\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n      case T_COMMA: scan(&Token); break;\n      case T_RPAREN: break;\n      default:\n        fatald(\"Unexpected token in parameter list\", Token.token);\n    }\n  }\n\n  // Return the count of parameters\n  return(paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function.\n// The identifier has been scanned & we have the type\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int nameslot, endlabel, paramcnt;\n\n  // Text now has the identifier's name.\n  // Get a label-id for the end label, add the function\n  // to the symbol table, and set the Functionid global\n  // to the function's symbol-id\n  endlabel = genlabel();\n  nameslot = addglob(Text, type, S_FUNCTION, endlabel, 0);\n  Functionid = nameslot;\n\n  // Scan in the parentheses and any parameters\n  // Update the function symbol entry with the number of parameters\n  lparen();\n  paramcnt= param_declaration();\n  Symtable[nameslot].nelems= paramcnt;\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, nameslot));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration and\n      // generate the assembly code for it\n      tree = function_declaration(type);\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, 0, 0);\n      semi();\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "24_Function_Params/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(int id);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id, int op);\nint cgloadlocal(int id, int op);\nint cgloadglobstr(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(int r, int id);\nint cgstorglob(int r, int id);\nint cgstorlocal(int r, int id);\nvoid cgglobsym(int id);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint findlocl(char *s);\nint findsymbol(char *s);\nint addglob(char *name, int type, int stype, int endlabel, int size);\nint addlocl(char *name, int type, int stype, int isparam, int size);\nvoid freeloclsyms(void);\n\n// decl.c\nvoid var_declaration(int type, int islocal, int isparam);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint parse_type(void);\nint pointer_to(int type);\nint value_at(int type);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "24_Function_Params/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND, \n  T_OR, T_XOR, T_AMPER, \n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN= 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n#define NOLABEL\t 0\t\t// Use NOLABEL when we have no label to\n\t\t\t\t// pass to genAST()\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n        C_GLOBAL = 1,\t\t// Globally visible symbol\n        C_LOCAL,\t\t// Locally visible symbol\n        C_PARAM\t\t\t// Locally visible function parameter\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n  int size;\t\t\t// Number of elements in the symbol\n  int posn;\t\t\t// For locals, either the negative offset\n\t\t\t\t// from stack base pointer, or register id\n#define nelems posn\t\t// For functions, # of params\n\t\t\t\t// For structs, # of fields\n};\n"
  },
  {
    "path": "24_Function_Params/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Parse a function call with a single expression\n// argument and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Symtable[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and\n// return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  int id;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, Symtable[id].type, id);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, Symtable[id].type, left, NULL, right, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  int id;\n\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // A variable. Check that the variable exists.\n  id = findsymbol(Text);\n  if (id == -1 || Symtable[id].stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n      // Post-increment: skip over the token\n    case T_INC:\n      scan(&Token);\n      n = mkastleaf(A_POSTINC, Symtable[id].type, id);\n      break;\n\n      // Post-decrement: skip over the token\n    case T_DEC:\n      scan(&Token);\n      n = mkastleaf(A_POSTDEC, Symtable[id].type, id);\n      break;\n\n      // Just a variable reference\n    default:\n      n = mkastleaf(A_IDENT, Symtable[id].type, id);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n\tn = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n      break;\n\n    case T_STRLIT:\n      // For a STRLIT token, generate the assembly for it.\n      // Then make a leaf AST node for it. id is the string's label.\n      id = genglobstr(Text);\n      n = mkastleaf(A_STRLIT, P_CHARPTR, id);\n      break;\n\n    case T_IDENT:\n      return (postfix());\n\n    case T_LPAREN:\n      // Beginning of a parenthesised expression, skip the '('.\n      // Scan in the expression and the right parenthesis\n      scan(&Token);\n      n = binexpr(0);\n      rparen();\n      return (n);\n\n    default:\n      fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n    case T_AMPER:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Ensure that it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"& operator must be followed by an identifier\");\n\n      // Now change the operator to A_ADDR and the type to\n      // a pointer to the original type\n      tree->op = A_ADDR;\n      tree->type = pointer_to(tree->type);\n      break;\n    case T_STAR:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's either another deref or an\n      // identifier\n      if (tree->op != A_IDENT && tree->op != A_DEREF)\n\tfatal(\"* operator must be followed by an identifier or *\");\n\n      // Prepend an A_DEREF operation to the tree\n      tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n      break;\n    case T_MINUS:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_NEGATE operation to the tree and\n      // make the child an rvalue. Because chars are unsigned,\n      // also widen this to int so that it's signed\n      tree->rvalue = 1;\n      tree = modify_type(tree, P_INT, 0);\n      tree = mkastunary(A_NEGATE, tree->type, tree, 0);\n      break;\n    case T_INVERT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_INVERT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_INVERT, tree->type, tree, 0);\n      break;\n    case T_LOGNOT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_LOGNOT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_LOGNOT, tree->type, tree, 0);\n      break;\n    case T_INC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"++ operator must be followed by an identifier\");\n\n      // Prepend an A_PREINC operation to the tree\n      tree = mkastunary(A_PREINC, tree->type, tree, 0);\n      break;\n    case T_DEC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"-- operator must be followed by an identifier\");\n\n      // Prepend an A_PREDEC operation to the tree\n      tree = mkastunary(A_PREDEC, tree->type, tree, 0);\n      break;\n    default:\n      tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit a semicolon or ')', return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN || tokentype == T_RBRACKET) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (left == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(binastop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a semicolon, ')' or ']', return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN\n\t|| tokentype == T_RBRACKET) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "24_Function_Params/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOLABEL, n->op);\n      genfreeregs();\n      genAST(n->right, NOLABEL, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->v.id);\n      genAST(n->left, NOLABEL, n->op);\n      cgfuncpostamble(n->v.id);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->v.id));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (Symtable[n->v.id].class == C_GLOBAL) {\n\t  return (cgloadglob(n->v.id, n->op));\n\t} else {\n\t  return (cgloadlocal(n->v.id, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (Symtable[n->right->v.id].class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->v.id));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->v.id));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_FUNCCALL:\n      return (cgcall(leftreg, n->v.id));\n    case A_ADDR:\n      return (cgaddress(n->v.id));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->v.size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->v.size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n      // Load the variable's value into a register,\n      // then increment it\n      return (cgloadglob(n->v.id, n->op));\n    case A_POSTDEC:\n      // Load the variable's value into a register,\n      // then decrement it\n      return (cgloadglob(n->v.id, n->op));\n    case A_PREINC:\n      // Load and increment the variable's value into a register\n      return (cgloadglob(n->left->v.id, n->op));\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      return (cgloadglob(n->left->v.id, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, label));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "24_Function_Params/input27a.c",
    "content": "int param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printint(a); printint(b); printint(c); printint(d);\n  printint(e); printint(f); printint(g); printint(h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/input27b.c",
    "content": "#include <stdio.h>\nextern int param8(int a, int b, int c, int d, int e, int f, int g, int h);\nextern int param5(int a, int b, int c, int d, int e);\nextern int param2(int a, int b);\nextern int param0();\n\nint main() {\n  param8(1,2,3,4,5,6,7,8); puts(\"--\");\n  param5(1,2,3,4,5); puts(\"--\");\n  param2(1,2); puts(\"--\");\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n\nvoid printchar(long x) {\n  putc((char)(x & 0x7f), stdout);\n}\n"
  },
  {
    "path": "24_Function_Params/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n  Globs = 0;\n  Locls = NSYMBOLS - 1;\n  O_dumpAST = 0;\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-T] infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nint main(int argc, char *argv[]) {\n  int i;\n\n  // Initialise the globals\n  init();\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    if (*argv[i] != '-')\n      break;\n    for (int j = 1; argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have an input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Open up the input file\n  if ((Infile = fopen(argv[i], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[i], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n  // For now, ensure that printint() and printchar() are defined\n  addglob(\"printint\", P_INT, S_FUNCTION, 0, 0);\n  addglob(\"printchar\", P_VOID, S_FUNCTION, 0, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  return (0);\n}\n"
  },
  {
    "path": "24_Function_Params/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "24_Function_Params/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "24_Function_Params/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Symtable[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Symtable[Functionid].type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration\n      // and skip over the semicolon\n      type = parse_type();\n      ident();\n      var_declaration(type, 1, 0);\n      semi();\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "24_Function_Params/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\n// Skip C_PARAM entries\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (Symtable[i].class == C_PARAM) continue;\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= Locls)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return its slot position or -1 if not found.\nint findlocl(char *s) {\n  int i;\n\n  for (i = Locls + 1; i < NSYMBOLS; i++) {\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new local symbol slot, or die\n// if we've run out of positions.\nstatic int newlocl(void) {\n  int p;\n\n  if ((p = Locls--) <= Globs)\n    fatal(\"Too many local symbols\");\n  return (p);\n}\n\n// Clear all the entries in the\n// local symbol table\nvoid freeloclsyms(void) {\n  Locls = NSYMBOLS - 1;\n}\n\n// Update a symbol at the given slot number in the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + endlabel: if this is a function\n// + posn: Position information for local symbols\nstatic void updatesym(int slot, char *name, int type, int stype,\n\t\t      int class, int endlabel, int size, int posn) {\n  if (slot < 0 || slot >= NSYMBOLS)\n    fatal(\"Invalid symbol slot number in updatesym()\");\n  Symtable[slot].name = strdup(name);\n  Symtable[slot].type = type;\n  Symtable[slot].stype = stype;\n  Symtable[slot].class = class;\n  Symtable[slot].endlabel = endlabel;\n  Symtable[slot].size = size;\n  Symtable[slot].posn = posn;\n}\n\n// Add a global symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + endlabel: if this is a function\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int endlabel, int size) {\n  int slot;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((slot = findglob(name)) != -1)\n    return (slot);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  slot = newglob();\n  updatesym(slot, name, type, stype, C_GLOBAL, endlabel, size, 0);\n  genglobsym(slot);\n  return (slot);\n}\n\n// Add a local symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + isparam: if true, this is a parameter to the function\n// Return the slot number in the symbol table, -1 if a duplicate entry\nint addlocl(char *name, int type, int stype, int isparam, int size) {\n  int localslot, globalslot;\n\n  // If this is already in the symbol table, return an error\n  if ((localslot = findlocl(name)) != -1)\n    return (-1);\n\n  // Otherwise get a new symbol slot and a position for this local.\n  // Update the local symbol table entry. If this is a parameter,\n  // also create a global C_PARAM entry to build the function's prototype.\n  localslot = newlocl();\n  if (isparam) {\n    updatesym(localslot, name, type, stype, C_PARAM, 0, size, 0);\n    globalslot = newglob();\n    updatesym(globalslot, name, type, stype, C_PARAM, 0, size, 0);\n  } else {\n    updatesym(localslot, name, type, stype, C_LOCAL, 0, size, 0);\n  }\n\n  // Return the local symbol's slot\n  return (localslot);\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return its slot position or -1 if not found.\nint findsymbol(char *s) {\n  int slot;\n\n  slot = findlocl(s);\n  if (slot == -1)\n    slot = findglob(s);\n  return (slot);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input01.c",
    "content": "void main()\n{ printint(12 * 3);\n  printint(18 - 2 * 4);\n  printint(1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input02.c",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printint(fred + jim);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input03.c",
    "content": "void main()\n{\n  int x;\n  x= 1;     printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input04.c",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  printint(x);\n  x= 7 <= 9; printint(x);\n  x= 7 != 9; printint(x);\n  x= 7 == 7; printint(x);\n  x= 7 >= 7; printint(x);\n  x= 7 <= 7; printint(x);\n  x= 9 > 7;  printint(x);\n  x= 9 >= 7; printint(x);\n  x= 9 != 7; printint(x);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input05.c",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printint(i);\n  } else {\n    printint(j);\n  }\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input06.c",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printint(i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input07.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input08.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input09.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printint(2 * b - a); }\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input10.c",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; printint(j);\n  i= 10; printint(i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 2; j= j + 1) { printint(j); }\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input11.c",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; printint(i);\n  j= 20; printint(j);\n  k= 30; printint(k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 4; j= j + 1) { printint(j); }\n  for (k= 1;   k <= 5; k= k + 1) { printint(k); }\n  return(i);\n  printint(12345);\n  return(3);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input12.c",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printint(x);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input13.c",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input14.c",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input15.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printint(a);\n  b= &a; c= *b; printint(c);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input16.c",
    "content": "int   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printint(c);\n  e= &c + 1; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input17.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printint(a);\n  e= &d; *e= 12; printint(d);\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input18.c",
    "content": "int main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printint(a);\n  printint(b);\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input18a.c",
    "content": "int   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printint(a);\n  d= &c; *d= 16; printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input19.c",
    "content": "int a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printint(e);\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input20.c",
    "content": "int a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printint(a);\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input21.c",
    "content": "char  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printint(c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printchar(*str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input22.c",
    "content": "char a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printint(a);\n  e= 5; f= 7; d= e + f++; printint(d);\n  h= 5; i= 7; g= h + i++; printint(g);\n  a= b-- + c; printint(a);\n  d= e-- + f; printint(d);\n  g= h-- + i; printint(g);\n  a= ++b + c; printint(a);\n  d= ++e + f; printint(d);\n  g= ++h + i; printint(g);\n  a= b * --c; printint(a);\n  d= e * --f; printint(d);\n  g= h * --i; printint(g);\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input23.c",
    "content": "char *str;\nint   x;\n\nint main() {\n  x= -23; printint(x);\n  printint(-10 * -10);\n\n  x= 1; x= ~x; printint(x);\n\n  x= 2 > 5; printint(x);\n  x= !x; printint(x);\n  x= !x; printint(x);\n\n  x= 13; if (x) { printint(13); }\n  x= 0; if (!x) { printint(14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printchar(*str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input24.c",
    "content": "int a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printint(a & b);\n  printint(a | b);\n  printint(a ^ b);\n  printint(1 << 3);\n  printint(63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input25.c",
    "content": "int a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printint(x); printint(y); printint(z);\n  a= 5; b= 15; c= 25;\n  printint(a); printint(b); printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/input26.c",
    "content": "int main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printint(a);\n  b= 23; printint(b);\n  c= 34; printint(c);\n  d= 44; printint(d);\n  e= 54; printint(e);\n  f= 64; printint(f);\n  g= 74; printint(g);\n  h= 84; printint(h);\n  i= 94; printint(i);\n  j= 95; printint(j);\n  k= 96; printint(k);\n  return(0);\n}\n"
  },
  {
    "path": "24_Function_Params/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" ]\n   then\n     cc -o out $i ../lib/printint.c\n     ./out > out.$i\n     rm -f out\n   fi\ndone\n"
  },
  {
    "path": "24_Function_Params/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "24_Function_Params/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "24_Function_Params/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "24_Function_Params/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "24_Function_Params/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "24_Function_Params/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "24_Function_Params/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "24_Function_Params/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "24_Function_Params/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "24_Function_Params/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "24_Function_Params/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "24_Function_Params/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "24_Function_Params/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "24_Function_Params/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "24_Function_Params/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "24_Function_Params/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "24_Function_Params/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "24_Function_Params/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "24_Function_Params/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "24_Function_Params/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "24_Function_Params/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "24_Function_Params/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "24_Function_Params/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "24_Function_Params/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "24_Function_Params/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "24_Function_Params/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "24_Function_Params/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "24_Function_Params/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "24_Function_Params/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -Wall -o out out.o ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "24_Function_Params/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->v.intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->v.id);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", Symtable[n->v.id].name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->v.size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "24_Function_Params/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  if (type == P_CHAR || type == P_INT || type == P_LONG)\n    return (1);\n  return (0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  if (type == P_VOIDPTR || type == P_CHARPTR ||\n      type == P_INTPTR || type == P_LONGPTR)\n    return (1);\n  return (0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOID:\n      newtype = P_VOIDPTR;\n      break;\n    case P_CHAR:\n      newtype = P_CHARPTR;\n      break;\n    case P_INT:\n      newtype = P_INTPTR;\n      break;\n    case P_LONG:\n      newtype = P_LONGPTR;\n      break;\n    default:\n      fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOIDPTR:\n      newtype = P_VOID;\n      break;\n    case P_CHARPTR:\n      newtype = P_CHAR;\n      break;\n    case P_INTPTR:\n      newtype = P_INT;\n      break;\n    case P_LONGPTR:\n      newtype = P_LONG;\n      break;\n    default:\n      fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "25_Function_Arguments/Makefile",
    "content": "HSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncomp1: $(SRCS) $(HSRCS)\n\tcc -o comp1 -g -Wall $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -o compn -g -Wall $(SRCN)\n\ncomp1arm: $(ARMSRCS) $(HSRCS)\n\tcc -o comp1arm -g -Wall $(ARMSRCS)\n\tcp comp1arm comp1\n\nclean:\n\trm -f comp1 comp1arm compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: comp1arm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "25_Function_Arguments/Readme.md",
    "content": "# Part 25: Function Calls and Arguments\n\nIn this part of our compiler writing journey, I'm going to add the ability\nto call functions with an arbitrary number of arguments; the argument's\nvalues will be copied into the function's parameters and appear as\nlocal variables.\n\nI haven't done this yet, because there is a bit of design thinking to be\ndone before the coding can begin. Once more, let's review\nthe image from Eli Bendersky's article on the\n[stack frame layout on x86-64](https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/).\n\n![](../22_Design_Locals/Figs/x64_frame_nonleaf.png)\n\nUp to six \"call by value\" arguments to a function are passed in via the\nregisters `%rdi` to `%r9`. For more than six arguments, the remaining arguments\nare pushed on the stack.\n\nLook closely at the argument values on the stack. Even though `h` is the\nlast argument, it is pushed first on the stack (which grows downwards),\nand the `g` argument is pushed *after* the `h` argument.\n\nOne of the *Bad Things* about C is that there is no defined order of\nexpression evaluation. As noted\n[here](https://en.cppreference.com/w/c/language/eval_order):\n\n> [The] order of evaluation of the operands of any C operator, including\n  the order of evaluation of function arguments in a function-call\n  expression ... is unspecified ... . The compiler will evaluate them\n  in any order ...\n\nThis makes the language potentially unportable: the behaviour of code\non one platform with one compiler may have different behaviour on a\ndifferent platform or when compiled with a different compiler.\n\nFor us, though, this lack of defined evaluation order is a *Good Thing*,\nonly because we can generate our argument values in the order that\nmakes it easier to write our compiler. I'm being flippant here: this\nis really not much of a good thing.\n\nBecause the x86-64 platform expects the last argument's value to be pushed\non the stack first, I'll need to write the code to process arguments from\nthe last to the first. I should make sure that the code could be easily\naltered to allow processing in the other direction: perhaps a `genXXX()`\nquery function could be written to tell our code which direction to process\nthe arguments. I'll leave that to be written later.\n\n### Generating an AST of Expressions\n\nWe already have the A_GLUE AST node type, so it should be easy to\nwrite a function to parse the argument expressions and build an AST tree.\nFor a function call `function(expr1, expr2, expr3, expr4)`, I've decided\nto build the tree like this:\n\n```\n                 A_FUNCCALL\n                  /\n              A_GLUE\n               /   \\\n           A_GLUE  expr4\n            /   \\\n        A_GLUE  expr3\n         /   \\\n     A_GLUE  expr2\n     /    \\\n   NULL  expr1\n```\n\nEach expression is on the right, and previous expressions are on the left.\nI will have to traverse the sub-tree of expressions right to left, to\nensure that I process `expr4` before `expr3` in case the former has to\nbe pushed on the x86-64 stack before the latter.\n\nWe already have a `funccall()` function to parse a simple function call\nwith always one argument. I'll modify this to call an `expression_list()`\nfunction to parse the expression list and build the A_GLUE sub-tree. It\nwill return a count of the number of expressions by storing this count\nin the top A_GLUE AST node. Then, in `funccall()`, we can check the type\nof all the expressions against the function's prototype which should be\nstored in the global symbol table.\n\nI think that's enough on the design side of things. Let's now get on\nto the implementation.\n\n## Expression Parsing Changes\n\nWell, I got the code done in an hour or so and I'm pleasantly surprised. To\nborrow a quote that floats around on Twitter:\n\n> Weeks of programming can save you hours of planning.\n\nConversely, a bit of time spent on design always helps with\nthe efficiency of coding.\nLet's have a look at the changes. We'll start with the parsing.\n\nWe now have to parse a comma-separated list of expressions, and build that\nA_GLUE AST tree with child expressions on the right, and previous expression\ntrees on the left. Here is the code in `expr.c`:\n\n```c\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n      case T_COMMA:\n        scan(&Token);\n        break;\n      case T_RPAREN:\n        break;\n      default:\n        fatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n```\n\nThat turned out to be much easier to code than I was expecting. Now, we need\nto interface this with the existing function call parser:\n\n```c\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Symtable[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n```\n\nNote the `XXX` which is my reminder that I still have work to perform.\nThe parser does check that the function has previously been declared,\nbut as yet it doesn't compare the argument types against the function's\nprototype. I'll do that soon.\n\nThe AST tree that is returned now has the shape that I drew up near the\nbeginning of this article. Now it's time to walk it and generate assembly code.\n\n## Changes to the Generic Code Generator\n\nThe way the compiler is written, the code that walks the AST  is\narchitecture-neutral is in `gen.c`, and the actual platform-dependent\nback-end is in `cg.c`. So we start with the changes to `gen.c`.\n\nThere is a non-trivial amount of code needed to walk this new AST structure,\nso I now have a function to deal with function calls. In `genAST()` we now\nhave:\n\n```c\n  // n is the AST node being processed\n  switch (n->op) {\n    ...\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n  }\n```\n\nThe code to walk the new AST structure is here:\n\n```c\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs=0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->v.size);\n    // Keep the first (highest) number of arguments\n    if (numargs==0) numargs= gluetree->v.size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->v.id, numargs));\n}\n```\n\nThere are a few things to note. We generate the expression code by\ncalling `genAST()` on the right child. Also, we set `numargs` to the\nfirst `size` value, which is the number of arguments (one-based not zero-based).\nThen we call `cgcopyarg()` to copy this value into the function's *n'th*\nparameter. Once the copy is done, we can free all our registers in preparation\nfor the next expression, and walk down the left child for the previous\nexpression.\n\nFinally, we run `cgcall()` to generate the actual call to the function.\nBecause we may have pushed argument values on the stack, we provide this\nwith the number of arguments in total so it can work out how many to pop\nback off the stack.\n\nThere is no hardware-specific code here but, as I mentioned at the top,\nwe are walking the expression tree from the last expression to the first.\nNot all architectures will want this, so there is room to make the code\nmore flexible in terms of the order of evaluation.\n\n## Changes to `cg.c`\n\nNow we get to the functions that generate actual x86-64 assembly code output.\nWe have created a new one, `cgcopyarg()`, and modified an existing one,\n`cgcall()`.\n\nBut first, a reminder that we have these lists of registers:\n\n```c\n#define FIRSTPARAMREG 9         // Position of first parameter register\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\", \"%rdi\" };\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\", \"%dil\" };\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\", \"%esi\", \"%edi\" };\n```\n\nwith FIRSTPARAMREG set to the last index position: we will walk backwards down\nthis list.\n\nAlso, remember that the argument position numbers we will get are one-based\n(i.e 1, 2, 3, 4, ...) not zero-based (0, 1, 2, 3, ...), but the array above\nis zero-based. You will see a few `+1` or `-1` adjustments in the code below.\n\nHere is `cgcopyarg()`:\n\n```c\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n            reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n```\n\nNice and simple except for the `+1`. Now the code for `cgcall()`:\n\n```c\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(int id, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Symtable[id].name);\n  // Remove any arguments pushed on the stack\n  if (numargs>6) \n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8*(numargs-6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n```\n\nAgain, nice and simple.\n\n## Testing the Changes\n\nIn the last part of our compiler writing journey, we had two separate\ntest programs `input27a.c` and `input27b.c`: we had to compile one of\nthem with `gcc`. Now, we can combine them together and compile it all\nwith our compiler. There is a second test program `input28.c` with\nsome more examples of function calling. As always:\n\n```\n$ make test\ncc -o comp1 -g -Wall cg.c decl.c expr.c gen.c main.c\n    misc.c scan.c stmt.c sym.c tree.c types.c\n(cd tests; chmod +x runtests; ./runtests)\n  ...\ninput25.c: OK\ninput26.c: OK\ninput27.c: OK\ninput28.c: OK\n```\n\n## Conclusion and What's Next\n\nRight now, I feel that our compiler has just gone from being a \"toy\" compiler\nto one which is nearly useful: we can now write multi-function programs\nand call between the functions. It took a few steps to get there, but\nI think each step was not a giant one.\n\nThere is obviously still a big journey left. We need to add structs,\nunions, external identifiers and a pre-processor. Then we have to make\nthe compiler more robust, provide better error detections, possibly\nadd warnings etc. So, perhaps we are about half-way at this point.\n\nIn the next part of our compiler writing journey, I think I'm going to\nadd the ability to write function prototypes. This will allow us to\nlink in outside functions. I'm thinking of those original Unix functions\nand system calls which are `int` and `char *` based such as `open()`,\n`read()`, `write()`, `strcpy()` etc. It will be nice to compile\nsome useful programs with our compiler. [Next step](../26_Prototypes/Readme.md)\n"
  },
  {
    "path": "25_Function_Arguments/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  int i;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack\n  // Stop after no more than six parameter registers\n  for (i = NSYMBOLS - 1; i > Locls; i--) {\n    if (Symtable[i].class != C_PARAM)\n      break;\n    if (i < NSYMBOLS - 6)\n      break;\n    Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    cgstorlocal(paramReg--, i);\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (; i > Locls; i--) {\n    if (Symtable[i].class == C_PARAM) {\n      Symtable[i].posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    }\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", id, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(int id, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Symtable[id].name);\n  // Remove any arguments pushed on the stack\n  if (numargs>6) \n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8*(numargs-6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r],\n\t      Symtable[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r],\n\t      Symtable[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r],\n\t      Symtable[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r],\n\t      Symtable[id].posn);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r],\n\t      Symtable[id].posn);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r],\n\t      Symtable[id].posn);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch (typesize) {\n      case 1:\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"\\t.long\\t0\\n\");\n\tbreak;\n      case 8:\n\tfprintf(Outfile, \"\\t.quad\\t0\\n\");\n\tbreak;\n      default:\n\tfatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_LOCAL)\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "25_Function_Arguments/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4, 4, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "25_Function_Arguments/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  int i;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack\n  // Stop after no more than six parameter registers\n  for (i = NSYMBOLS - 1; i > Locls; i--) {\n    if (Symtable[i].class != C_PARAM)\n      break;\n    if (i < NSYMBOLS - 6)\n      break;\n    Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    cgstorlocal(paramReg--, i);\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (; i > Locls; i--) {\n    if (Symtable[i].class == C_PARAM) {\n      Symtable[i].posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    }\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Symtable[id].name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              Symtable[id].name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Symtable[id].name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              Symtable[id].posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n              Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n              Symtable[id].posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], id);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(int id, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Symtable[id].name);\n  // Remove any arguments pushed on the stack\n  if (numargs>6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8*(numargs-6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  // original version\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch(typesize) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(typesize) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", Symtable[id].size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", Symtable[id].size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", Symtable[id].size);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_LOCAL)\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            Symtable[id].posn);\n  else\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Symtable[id].name);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "25_Function_Arguments/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ int Locls;\t\t// Position of next free local symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Symtable[NSYMBOLS];\t// Global symbol table\n\nextern_ int O_dumpAST;\n"
  },
  {
    "path": "25_Function_Arguments/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      break;\n    case T_INT:\n      type = P_INT;\n      break;\n    case T_LONG:\n      type = P_LONG;\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type\n// islocal is set if this is a local variable\n// isparam is set if this local variable is a function parameter\nvoid var_declaration(int type, int islocal, int isparam) {\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      if (islocal) {\n\tfatal(\"For now, declaration of local arrays is not implemented\");\n      } else {\n\taddglob(Text, pointer_to(type), S_ARRAY, 0, Token.intvalue);\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    if (islocal) {\n      if (addlocl(Text, type, S_VARIABLE, isparam, 1)==-1)\n       fatals(\"Duplicate local variable declaration\", Text);\n    } else {\n      addglob(Text, type, S_VARIABLE, 0, 1);\n    }\n  }\n}\n\n// param_declaration: <null>\n//           | variable_declaration\n//           | variable_declaration ',' param_declaration\n//\n// Parse the parameters in parentheses after the function name.\n// Add them as symbols to the symbol table and return the number\n// of parameters.\nstatic int param_declaration(void) {\n  int type;\n  int paramcnt=0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n    // Get the type and identifier\n    // and add it to the symbol table\n    type = parse_type();\n    ident();\n    var_declaration(type, 1, 1);\n    paramcnt++;\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n      case T_COMMA: scan(&Token); break;\n      case T_RPAREN: break;\n      default:\n        fatald(\"Unexpected token in parameter list\", Token.token);\n    }\n  }\n\n  // Return the count of parameters\n  return(paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' ')' compound_statement   ;\n//\n// Parse the declaration of a simplistic function.\n// The identifier has been scanned & we have the type\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int nameslot, endlabel, paramcnt;\n\n  // Text now has the identifier's name.\n  // Get a label-id for the end label, add the function\n  // to the symbol table, and set the Functionid global\n  // to the function's symbol-id\n  endlabel = genlabel();\n  nameslot = addglob(Text, type, S_FUNCTION, endlabel, 0);\n  Functionid = nameslot;\n\n  // Scan in the parentheses and any parameters\n  // Update the function symbol entry with the number of parameters\n  lparen();\n  paramcnt= param_declaration();\n  Symtable[nameslot].nelems= paramcnt;\n  rparen();\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's nameslot\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, nameslot));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration and\n      // generate the assembly code for it\n      tree = function_declaration(type);\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, 0, 0);\n      semi();\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "25_Function_Arguments/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(int id);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id, int op);\nint cgloadlocal(int id, int op);\nint cgloadglobstr(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(int id, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, int id);\nint cgstorlocal(int r, int id);\nvoid cgglobsym(int id);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint findlocl(char *s);\nint findsymbol(char *s);\nint addglob(char *name, int type, int stype, int endlabel, int size);\nint addlocl(char *name, int type, int stype, int isparam, int size);\nvoid freeloclsyms(void);\n\n// decl.c\nvoid var_declaration(int type, int islocal, int isparam);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint parse_type(void);\nint pointer_to(int type);\nint value_at(int type);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "25_Function_Arguments/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND, \n  T_OR, T_XOR, T_AMPER, \n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN= 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n#define NOLABEL\t 0\t\t// Use NOLABEL when we have no label to\n\t\t\t\t// pass to genAST()\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n        C_GLOBAL = 1,\t\t// Globally visible symbol\n        C_LOCAL,\t\t// Locally visible symbol\n        C_PARAM\t\t\t// Locally visible function parameter\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n  int size;\t\t\t// Number of elements in the symbol\n  int posn;\t\t\t// For locals, either the negative offset\n\t\t\t\t// from stack base pointer, or register id\n#define nelems posn\t\t// For functions, # of params\n\t\t\t\t// For structs, # of fields\n};\n"
  },
  {
    "path": "25_Function_Arguments/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n      case T_COMMA:\n\tscan(&Token);\n\tbreak;\n      case T_RPAREN:\n\tbreak;\n      default:\n\tfatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Symtable[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  int id;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, Symtable[id].type, id);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, Symtable[id].type, left, NULL, right, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  int id;\n\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // A variable. Check that the variable exists.\n  id = findsymbol(Text);\n  if (id == -1 || Symtable[id].stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n      // Post-increment: skip over the token\n    case T_INC:\n      scan(&Token);\n      n = mkastleaf(A_POSTINC, Symtable[id].type, id);\n      break;\n\n      // Post-decrement: skip over the token\n    case T_DEC:\n      scan(&Token);\n      n = mkastleaf(A_POSTDEC, Symtable[id].type, id);\n      break;\n\n      // Just a variable reference\n    default:\n      n = mkastleaf(A_IDENT, Symtable[id].type, id);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n\tn = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n      break;\n\n    case T_STRLIT:\n      // For a STRLIT token, generate the assembly for it.\n      // Then make a leaf AST node for it. id is the string's label.\n      id = genglobstr(Text);\n      n = mkastleaf(A_STRLIT, P_CHARPTR, id);\n      break;\n\n    case T_IDENT:\n      return (postfix());\n\n    case T_LPAREN:\n      // Beginning of a parenthesised expression, skip the '('.\n      // Scan in the expression and the right parenthesis\n      scan(&Token);\n      n = binexpr(0);\n      rparen();\n      return (n);\n\n    default:\n      fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n    case T_AMPER:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Ensure that it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"& operator must be followed by an identifier\");\n\n      // Now change the operator to A_ADDR and the type to\n      // a pointer to the original type\n      tree->op = A_ADDR;\n      tree->type = pointer_to(tree->type);\n      break;\n    case T_STAR:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's either another deref or an\n      // identifier\n      if (tree->op != A_IDENT && tree->op != A_DEREF)\n\tfatal(\"* operator must be followed by an identifier or *\");\n\n      // Prepend an A_DEREF operation to the tree\n      tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n      break;\n    case T_MINUS:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_NEGATE operation to the tree and\n      // make the child an rvalue. Because chars are unsigned,\n      // also widen this to int so that it's signed\n      tree->rvalue = 1;\n      tree = modify_type(tree, P_INT, 0);\n      tree = mkastunary(A_NEGATE, tree->type, tree, 0);\n      break;\n    case T_INVERT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_INVERT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_INVERT, tree->type, tree, 0);\n      break;\n    case T_LOGNOT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_LOGNOT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_LOGNOT, tree->type, tree, 0);\n      break;\n    case T_INC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"++ operator must be followed by an identifier\");\n\n      // Prepend an A_PREINC operation to the tree\n      tree = mkastunary(A_PREINC, tree->type, tree, 0);\n      break;\n    case T_DEC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"-- operator must be followed by an identifier\");\n\n      // Prepend an A_PREDEC operation to the tree\n      tree = mkastunary(A_PREDEC, tree->type, tree, 0);\n      break;\n    default:\n      tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (left == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(binastop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "25_Function_Arguments/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs=0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->v.size);\n    // Keep the first (highest) number of arguments\n    if (numargs==0) numargs= gluetree->v.size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->v.id, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOLABEL, n->op);\n      genfreeregs();\n      genAST(n->right, NOLABEL, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->v.id);\n      genAST(n->left, NOLABEL, n->op);\n      cgfuncpostamble(n->v.id);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->v.intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->v.id));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (Symtable[n->v.id].class == C_GLOBAL) {\n\t  return (cgloadglob(n->v.id, n->op));\n\t} else {\n\t  return (cgloadlocal(n->v.id, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (Symtable[n->right->v.id].class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->v.id));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->v.id));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->v.id));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->v.size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->v.size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n      // Load the variable's value into a register,\n      // then increment it\n      return (cgloadglob(n->v.id, n->op));\n    case A_POSTDEC:\n      // Load the variable's value into a register,\n      // then decrement it\n      return (cgloadglob(n->v.id, n->op));\n    case A_PREINC:\n      // Load and increment the variable's value into a register\n      return (cgloadglob(n->left->v.id, n->op));\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      return (cgloadglob(n->left->v.id, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, label));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "25_Function_Arguments/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n\nvoid printchar(long x) {\n  putc((char)(x & 0x7f), stdout);\n}\n"
  },
  {
    "path": "25_Function_Arguments/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n  Globs = 0;\n  Locls = NSYMBOLS - 1;\n  O_dumpAST = 0;\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-T] infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nint main(int argc, char *argv[]) {\n  int i;\n\n  // Initialise the globals\n  init();\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    if (*argv[i] != '-')\n      break;\n    for (int j = 1; argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have an input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Open up the input file\n  if ((Infile = fopen(argv[i], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[i], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n  // For now, ensure that printint() and printchar() are defined\n  addglob(\"printint\", P_INT, S_FUNCTION, 0, 0);\n  addglob(\"printchar\", P_VOID, S_FUNCTION, 0, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  return (0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "25_Function_Arguments/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "25_Function_Arguments/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Symtable[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Symtable[Functionid].type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration\n      // and skip over the semicolon\n      type = parse_type();\n      ident();\n      var_declaration(type, 1, 0);\n      semi();\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "25_Function_Arguments/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\n// Skip C_PARAM entries\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (Symtable[i].class == C_PARAM) continue;\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= Locls)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return its slot position or -1 if not found.\nint findlocl(char *s) {\n  int i;\n\n  for (i = Locls + 1; i < NSYMBOLS; i++) {\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new local symbol slot, or die\n// if we've run out of positions.\nstatic int newlocl(void) {\n  int p;\n\n  if ((p = Locls--) <= Globs)\n    fatal(\"Too many local symbols\");\n  return (p);\n}\n\n// Clear all the entries in the\n// local symbol table\nvoid freeloclsyms(void) {\n  Locls = NSYMBOLS - 1;\n}\n\n// Update a symbol at the given slot number in the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + endlabel: if this is a function\n// + posn: Position information for local symbols\nstatic void updatesym(int slot, char *name, int type, int stype,\n\t\t      int class, int endlabel, int size, int posn) {\n  if (slot < 0 || slot >= NSYMBOLS)\n    fatal(\"Invalid symbol slot number in updatesym()\");\n  Symtable[slot].name = strdup(name);\n  Symtable[slot].type = type;\n  Symtable[slot].stype = stype;\n  Symtable[slot].class = class;\n  Symtable[slot].endlabel = endlabel;\n  Symtable[slot].size = size;\n  Symtable[slot].posn = posn;\n}\n\n// Add a global symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + endlabel: if this is a function\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int endlabel, int size) {\n  int slot;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((slot = findglob(name)) != -1)\n    return (slot);\n\n  // Otherwise get a new slot, fill it in and\n  // return the slot number\n  slot = newglob();\n  updatesym(slot, name, type, stype, C_GLOBAL, endlabel, size, 0);\n  genglobsym(slot);\n  return (slot);\n}\n\n// Add a local symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + isparam: if true, this is a parameter to the function\n// Return the slot number in the symbol table, -1 if a duplicate entry\nint addlocl(char *name, int type, int stype, int isparam, int size) {\n  int localslot, globalslot;\n\n  // If this is already in the symbol table, return an error\n  if ((localslot = findlocl(name)) != -1)\n    return (-1);\n\n  // Otherwise get a new symbol slot and a position for this local.\n  // Update the local symbol table entry. If this is a parameter,\n  // also create a global C_PARAM entry to build the function's prototype.\n  localslot = newlocl();\n  if (isparam) {\n    updatesym(localslot, name, type, stype, C_PARAM, 0, size, 0);\n    globalslot = newglob();\n    updatesym(globalslot, name, type, stype, C_PARAM, 0, size, 0);\n  } else {\n    updatesym(localslot, name, type, stype, C_LOCAL, 0, size, 0);\n  }\n\n  // Return the local symbol's slot\n  return (localslot);\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return its slot position or -1 if not found.\nint findsymbol(char *s) {\n  int slot;\n\n  slot = findlocl(s);\n  if (slot == -1)\n    slot = findglob(s);\n  return (slot);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input01.c",
    "content": "void main()\n{ printint(12 * 3);\n  printint(18 - 2 * 4);\n  printint(1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input02.c",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printint(fred + jim);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input03.c",
    "content": "void main()\n{\n  int x;\n  x= 1;     printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input04.c",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  printint(x);\n  x= 7 <= 9; printint(x);\n  x= 7 != 9; printint(x);\n  x= 7 == 7; printint(x);\n  x= 7 >= 7; printint(x);\n  x= 7 <= 7; printint(x);\n  x= 9 > 7;  printint(x);\n  x= 9 >= 7; printint(x);\n  x= 9 != 7; printint(x);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input05.c",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printint(i);\n  } else {\n    printint(j);\n  }\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input06.c",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printint(i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input07.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input08.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input09.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printint(2 * b - a); }\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input10.c",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; printint(j);\n  i= 10; printint(i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 2; j= j + 1) { printint(j); }\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input11.c",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; printint(i);\n  j= 20; printint(j);\n  k= 30; printint(k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 4; j= j + 1) { printint(j); }\n  for (k= 1;   k <= 5; k= k + 1) { printint(k); }\n  return(i);\n  printint(12345);\n  return(3);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input12.c",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printint(x);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input13.c",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input14.c",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input15.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printint(a);\n  b= &a; c= *b; printint(c);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input16.c",
    "content": "int   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printint(c);\n  e= &c + 1; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input17.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printint(a);\n  e= &d; *e= 12; printint(d);\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input18.c",
    "content": "int main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printint(a);\n  printint(b);\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input18a.c",
    "content": "int   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printint(a);\n  d= &c; *d= 16; printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input19.c",
    "content": "int a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printint(e);\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input20.c",
    "content": "int a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printint(a);\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input21.c",
    "content": "char  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printint(c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printchar(*str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input22.c",
    "content": "char a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printint(a);\n  e= 5; f= 7; d= e + f++; printint(d);\n  h= 5; i= 7; g= h + i++; printint(g);\n  a= b-- + c; printint(a);\n  d= e-- + f; printint(d);\n  g= h-- + i; printint(g);\n  a= ++b + c; printint(a);\n  d= ++e + f; printint(d);\n  g= ++h + i; printint(g);\n  a= b * --c; printint(a);\n  d= e * --f; printint(d);\n  g= h * --i; printint(g);\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input23.c",
    "content": "char *str;\nint   x;\n\nint main() {\n  x= -23; printint(x);\n  printint(-10 * -10);\n\n  x= 1; x= ~x; printint(x);\n\n  x= 2 > 5; printint(x);\n  x= !x; printint(x);\n  x= !x; printint(x);\n\n  x= 13; if (x) { printint(13); }\n  x= 0; if (!x) { printint(14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printchar(*str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input24.c",
    "content": "int a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printint(a & b);\n  printint(a | b);\n  printint(a ^ b);\n  printint(1 << 3);\n  printint(63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input25.c",
    "content": "int a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printint(x); printint(y); printint(z);\n  a= 5; b= 15; c= 25;\n  printint(a); printint(b); printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input26.c",
    "content": "int main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printint(a);\n  b= 23; printint(b);\n  c= 34; printint(c);\n  d= 44; printint(d);\n  e= 54; printint(e);\n  f= 64; printint(f);\n  g= 74; printint(g);\n  h= 84; printint(h);\n  i= 94; printint(i);\n  j= 95; printint(j);\n  k= 96; printint(k);\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input27.c",
    "content": "int param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printint(a); printint(b); printint(c); printint(d);\n  printint(e); printint(f); printint(g); printint(h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/input28.c",
    "content": "int param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printint(a); printint(b); printint(c); printint(d);\n  printint(e); printint(f); printint(g); printint(h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printint(x);\n  return(0);\n}\n"
  },
  {
    "path": "25_Function_Arguments/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" ]\n   then\n     cc -o out $i ../lib/printint.c\n     ./out > out.$i\n     rm -f out\n   fi\ndone\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "25_Function_Arguments/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "25_Function_Arguments/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "25_Function_Arguments/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -Wall -o out out.o ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "25_Function_Arguments/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->v.intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->v.id);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", Symtable[n->v.id].name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->v.size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", Symtable[n->v.id].name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "25_Function_Arguments/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  if (type == P_CHAR || type == P_INT || type == P_LONG)\n    return (1);\n  return (0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  if (type == P_VOIDPTR || type == P_CHARPTR ||\n      type == P_INTPTR || type == P_LONGPTR)\n    return (1);\n  return (0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOID:\n      newtype = P_VOIDPTR;\n      break;\n    case P_CHAR:\n      newtype = P_CHARPTR;\n      break;\n    case P_INT:\n      newtype = P_INTPTR;\n      break;\n    case P_LONG:\n      newtype = P_LONGPTR;\n      break;\n    default:\n      fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n    case P_VOIDPTR:\n      newtype = P_VOID;\n      break;\n    case P_CHARPTR:\n      newtype = P_CHAR;\n      break;\n    case P_INTPTR:\n      newtype = P_INT;\n      break;\n    case P_LONGPTR:\n      newtype = P_LONG;\n      break;\n    default:\n      fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "26_Prototypes/Makefile",
    "content": "HSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncomp1: $(SRCS) $(HSRCS)\n\tcc -o comp1 -g -Wall $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -o compn -g -Wall $(SRCN)\n\ncomp1arm: $(ARMSRCS) $(HSRCS)\n\tcc -o comp1arm -g -Wall $(ARMSRCS)\n\tcp comp1arm comp1\n\nclean:\n\trm -f comp1 comp1arm compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: comp1arm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "26_Prototypes/Readme.md",
    "content": "# Part 26: Function Prototypes\n\nIn this part of our compiler writing journey, I've added the ability to\nwrite function prototypes. In the process, I've had to rewrite some of\nthe code that I'd just written in the previous parts; sorry about that.\nI didn't see far enough ahead!\n\nSo what do we want with function prototypes:\n\n + the ability to declare a function prototype with no body\n + the ability to declare a full function later on\n + to keep the prototype in the global symbol table section,\n   and the parameters as local variables in the local symbol table section\n + error checking on the number and types of parameters against a previous\n   function prototype\n\nAnd here is what I'm *not* going to do, at least not yet:\n\n + `function(void)`: this will be the same as the `function()` declaration\n + the declaration of a function with just the types, e.g.\n   `function(int ,char, long);` as this will make the parsing harder.\n   We can do this later.\n\n## What Functionality Needs to be Rewritten\n\nIn a recent part of our journey I added the declaration of a function\nwith parameters and a full function body. As we were parsing each\nparameter, I immediately added it to both the global symbol table\n(to form the prototype) and also the local symbol table (to be the\nfunction's parameters).\n\nNow that we want to implement function prototypes, it's not always true\nthat a parameter list will become the actual function's parameters. Consider\nthis function prototype:\n\n```c\n  int fred(char a, int foo, long bar);\n```\n\nWe can only define `fred` as a function, and `a`, `foo` and `bar` as\nthree parameters in the global symbol table. We have to wait until the\nfull function declaration before we can add `a`, `foo` and `bar` to\nthe local symbol table.\n\nI'll need to separate the definition of C_PARAM entries on the global symbol\ntable and on the local symbol table.\n\n## The Design of the New Parsing Mechanism\n\nHere is my quick design for the new function parsing mechanism which also\ndeals with prototypes.\n\n```\nGet the identifier and '('.\nSearch for the identifier in the symbol table.\nIf it exists, there is already a prototype: get the id position of\nthe function and its parammeter count.\n\nWhile parsing parameters:\n  - if a previous prototype, compare this param's type against the existing\n    one. Update the symbol's name in case this is a full function\n  - if no previous prototype, add the parameter to the symbol table\n\nEnsure # of params matches any existing prototype.\nParse the ')'. If ';' is next, done.\n\nIf '{' is next, copy the parameter list from the global symtable to the\nlocal sym table. Copy them in a loop so that they are put in reverse order\nin the local sym table.\n```\n\nI got this done in the last few hours, so here are the code changes.\n\n## Changes to `sym.c`\n\nI've changed the parameter list of a couple of functions in `sym.c`:\n\n```c\nint addglob(char *name, int type, int stype, int class, int endlabel, int size);\nint addlocl(char *name, int type, int stype, int class, int size);\n```\n\nPreviously, we had `addlocl()` also call `addglob()` to add a C_PARAM\nsymbol to both symbol tables. Now that we are separating this function,\nit makes sense to pass the actual class of the symbol to both functions.\n\nThere are calls to these functions in `main.c` and `decl.c`. I'll cover\nthe ones in `decl.c` later. The change in `main.c` is trivial.\n\nOnce we hit the declaration of a real function, we will need to copy\nits parameter list from the global to the local symbol table. As this is\nreally something specific to the symbol table, I've added this function to\n`sym.c`:\n\n```c\n// Given a function's slot number, copy the global parameters\n// from its prototype to be local parameters\nvoid copyfuncparams(int slot) {\n  int i, id = slot + 1;\n\n  for (i = 0; i < Symtable[slot].nelems; i++, id++) {\n    addlocl(Symtable[id].name, Symtable[id].type, Symtable[id].stype,\n            Symtable[id].class, Symtable[id].size);\n  }\n}\n```\n\n## Changes to `decl.c`\n\nNearly all of the changes to the compiler are confined to `decl.c`. We'll\nstart with the small ones and work up to the big ones.\n\n### `var_declaration()`\n\nI've changed the parameter list to `var_declaration()` in the same way\nthat I did for the `sym.c` functions:\n\n```c\nvoid var_declaration(int type, int class) {\n  ...\n  addglob(Text, pointer_to(type), S_ARRAY, class, 0, Token.intvalue);\n  ...\n  if (addlocl(Text, type, S_VARIABLE, class, 1) == -1)\n  ...\n  addglob(Text, type, S_VARIABLE, class, 0, 1);\n}\n```\n\nWe will use the ability to pass in the class in the other `decl.c`\nfunctions.\n\n### `param_declaration()`\n\nWe have big changes here, as we might already have a parameter list in\nthe global symbol table as an existing prototype. If we do, we need to\ncheck the number and types in the new list against the prototype.\n\n```c\n// Parse the parameters in parentheses after the function name.\n// Add them as symbols to the symbol table and return the number\n// of parameters. If id is not -1, there is an existing function\n// prototype, and the function has this symbol slot number.\nstatic int param_declaration(int id) {\n  int type, param_id;\n  int orig_paramcnt;\n  int paramcnt = 0;\n\n  // Add 1 to id so that it's either zero (no prototype), or\n  // it's the position of the zeroth existing parameter in\n  // the symbol table\n  param_id = id + 1;\n\n  // Get any existing prototype parameter count\n  if (param_id)\n    orig_paramcnt = Symtable[id].nelems;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n    // Get the type and identifier\n    // and add it to the symbol table\n    type = parse_type();\n    ident();\n\n    // We have an existing prototype.\n    // Check that this type matches the prototype.\n    if (param_id) {\n      if (type != Symtable[id].type)\n        fatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      param_id++;\n    } else {\n      // Add a new parameter to the new prototype\n      var_declaration(type, C_PARAM);\n    }\n    paramcnt++;\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in parameter list\", Token.token);\n    }\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((id != -1) && (paramcnt != orig_paramcnt))\n    fatals(\"Parameter count mismatch for function\", Symtable[id].name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n```\n\nRemember that the first parameter's global symbol table slot position\nis immediately after the slot for the function name's symbol. We get\npassed the slot position of an existing prototype, or -1 if there is\nno prototype.\n\nIt's a happy coincidence that we can add one to this to get the\nfirst parameter's slot number, or have 0 to indicate that there is no\nexisting prototype.\n\nWe still loop parsing each new parameter, but now there is new code\nto either compare against the existing prototype, or to add the\nparameter to the global symbol table.\n\nOnce we exit the loop, we can compare the number of parameters in this\nlist against the number in any existing prototype.\n\nRight now, the code feels a bit ugly and I'm sure that if I leave it\na while, I'll be able to see a way to refactor it a bit.\n\n### `function_declaration()`\n\nPreviously, this was a fairly simple function: get the type and name,\nadd a global symbol, read in the parameters, get the function's body\nand generate an AST tree for the function's code.\n\nNow, we have to deal with the fact this this might only be a prototype,\nor it could be a full function. And we won't know until we parse either the\n';' (for a prototype) or the '{' (for a full function). So let's take\nthe exposition of the code in stages.\n\n```c\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int id;\n  int nameslot, endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set id to -1\n  if ((id = findsymbol(Text)) != -1)\n    if (Symtable[id].stype != S_FUNCTION)\n      id = -1;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (id == -1) {\n    endlabel = genlabel();\n    nameslot = addglob(Text, type, S_FUNCTION, C_GLOBAL, endlabel, 0);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype symbol slot number\n  lparen();\n  paramcnt = param_declaration(id);\n  rparen();\n```\n\nThis is nearly the same as the previous version of the code, except that\n`id` is now set to -1 when there is no previous prototype or a positive\nnumber when there is a previous prototype. We only add the function's\nname to the global symbol table if it's not already there.\n\n```c\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters\n  if (id == -1)\n    Symtable[nameslot].nelems = paramcnt;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n```\n\nWe've got the count of parameters. If no previous prototype, update this\nprototype with this count. Now we can peek at the token after the end\nof the parameter list. If it's a semicolon, this is just a prototype.\nWe now have no AST tree to return, so skip the token and return NULL.\nI've had to slightly alter the code in `global_declarations()` to deal\nwith this NULL value: no big change.\n\nIf we continue on, we are now dealing with a full function declaration\nwith a body.\n\n```c\n  // This is not just a prototype.\n  // Copy the global parameters to be local parameters\n  if (id == -1)\n    id = nameslot;\n  copyfuncparams(id);\n```\n\nWe now need to copy the parameters from the prototype to the local symbol\ntable. The `id = nameslot` code is there for when we have just added\nthe global symbols ourselves and there was no previous prototype.\n\nThe rest of the code in `function_declaration()` is the same as before and\nI'll omit it. It checks that a non-void function does return a value, and\ngenerates the AST tree with an A_FUNCTION root node.\n\n## Testing the New Functionality\n\nOne of the drawbacks of the `tests/runtests` script is that it assumes\nthe compiler will definitely produce an assembly output file `out.s`\nwhich can be assembled and run. This prevents us from testing that the\ncompiler detects syntax and semantic errors.\n\nA quick *grep* of `decl.c` shows these new errors are detected:\n\n```c\nfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\nfatals(\"Parameter count mismatch for function\", Symtable[id].name);\n```\n\nThus, I'd better rewrite `tests/runtests` to verify that the compiler\ndoes detect these errors on bad input.\n\nWe do have two new working test programs, `input29.c` and `input30.c`.\nThe first one is the same as `input28.c` except that I've put the\nprototypes of all the functions at the top of the program:\n\n```c\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n```\n\nThis, and all previous test programs, still work. `input30.c`, though, is\nprobably the first non-trivial program that our compiler has been given.\nIt opens its own source file and prints it to standard output:\n\n```c\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n```\n\nWe can't yet call the pre-processor, so we manually put in the prototypes\nfor the `open()`, `read()`, `write()` and `close()` functions. We also\nhave to use 0 instead of O_RDONLY in the `open()` call.\n\nRight now, the compiler lets us declare a `char buf[60];` but we can't use\n`buf` itself as a char pointer. So I chose to assign a 60-character literal\nstring to a char pointer and we use this as the buffer.\n\nWe still also have to wrap IF and WHILE bodies with '{' ... '}' to make\nthem compound statements: I still haven't dealt with the dangling else\nproblem. Finally, we can't accept `char *argv[]` as a parameter declaration\nfor main yet, so I've had to hard-code the input file's name.\n\nStill, we now have a very primitive *cat(1)* program which our compiler\ncan compile! That's progress.\n\n\n## Conclusion and What's Next\n\nIn the next part of our compiler writing journey, I'll follow up on\na comment above and improve the testing of our compiler's functionality. [Next step](../27_Testing_Errors/Readme.md)\n"
  },
  {
    "path": "26_Prototypes/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  int i;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack\n  // Stop after no more than six parameter registers\n  for (i = NSYMBOLS - 1; i > Locls; i--) {\n    if (Symtable[i].class != C_PARAM)\n      break;\n    if (i < NSYMBOLS - 6)\n      break;\n    Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    cgstorlocal(paramReg--, i);\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (; i > Locls; i--) {\n    if (Symtable[i].class == C_PARAM) {\n      Symtable[i].posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    }\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n    break;\n  case P_INT:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    break;\n  case P_INT:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    break;\n  default:\n    fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", id, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(int id, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", Symtable[id].name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r],\n\t    Symtable[id].name);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r],\n\t    Symtable[id].name);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r],\n\t    Symtable[id].name);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r],\n\t    Symtable[id].posn);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r],\n\t    Symtable[id].posn);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r],\n\t    Symtable[id].posn);\n    break;\n  default:\n    fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n    break;\n  case P_LONG:\n    fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n    break;\n  default:\n    fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_LOCAL)\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n    fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  default:\n    fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  case P_LONG:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "26_Prototypes/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4, 4, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n  case 1:\n    fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n    break;\n  case 4:\n    fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n    break;\n  default:\n    fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n    break;\n  case P_INT:\n  case P_LONG:\n    fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "26_Prototypes/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  int i;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack\n  // Stop after no more than six parameter registers\n  for (i = NSYMBOLS - 1; i > Locls; i--) {\n    if (Symtable[i].class != C_PARAM)\n      break;\n    if (i < NSYMBOLS - 6)\n      break;\n    Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    cgstorlocal(paramReg--, i);\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (; i > Locls; i--) {\n    if (Symtable[i].class == C_PARAM) {\n      Symtable[i].posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    }\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Symtable[id].name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              Symtable[id].name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Symtable[id].name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              Symtable[id].posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n              Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n              Symtable[id].posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], id);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(int id, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Symtable[id].name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  // original version\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch(typesize) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(typesize) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", Symtable[id].size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", Symtable[id].size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", Symtable[id].size);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_LOCAL)\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            Symtable[id].posn);\n  else\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Symtable[id].name);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "26_Prototypes/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ int Locls;\t\t// Position of next free local symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Symtable[NSYMBOLS];\t// Global symbol table\n\nextern_ int O_dumpAST;\n"
  },
  {
    "path": "26_Prototypes/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n  case T_VOID:\n    type = P_VOID;\n    break;\n  case T_CHAR:\n    type = P_CHAR;\n    break;\n  case T_INT:\n    type = P_INT;\n    break;\n  case T_LONG:\n    type = P_LONG;\n    break;\n  default:\n    fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type.\n// class is the variable's class\nvoid var_declaration(int type, int class) {\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      if (class == C_LOCAL) {\n\tfatal(\"For now, declaration of local arrays is not implemented\");\n      } else {\n\taddglob(Text, pointer_to(type), S_ARRAY, class, 0, Token.intvalue);\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    if (class == C_LOCAL) {\n      if (addlocl(Text, type, S_VARIABLE, class, 1) == -1)\n\tfatals(\"Duplicate local variable declaration\", Text);\n    } else {\n      addglob(Text, type, S_VARIABLE, class, 0, 1);\n    }\n  }\n}\n\n// param_declaration: <null>\n//           | variable_declaration\n//           | variable_declaration ',' param_declaration\n//\n// Parse the parameters in parentheses after the function name.\n// Add them as symbols to the symbol table and return the number\n// of parameters. If id is not -1, there is an existing function\n// prototype, and the function has this symbol slot number.\nstatic int param_declaration(int id) {\n  int type, param_id;\n  int orig_paramcnt;\n  int paramcnt = 0;\n\n  // Add 1 to id so that it's either zero (no prototype), or\n  // it's the position of the zeroth existing parameter in\n  // the symbol table\n  param_id = id + 1;\n\n  // Get any existing prototype parameter count\n  if (param_id)\n    orig_paramcnt = Symtable[id].nelems;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n    // Get the type and identifier\n    // and add it to the symbol table\n    type = parse_type();\n    ident();\n\n    // We have an existing prototype.\n    // Check that this type matches the prototype.\n    if (param_id) {\n      if (type != Symtable[id].type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      param_id++;\n    } else {\n      // Add a new parameter to the new prototype\n      var_declaration(type, C_PARAM);\n    }\n    paramcnt++;\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in parameter list\", Token.token);\n    }\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((id != -1) && (paramcnt != orig_paramcnt))\n    fatals(\"Parameter count mismatch for function\", Symtable[id].name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int id;\n  int nameslot, endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set id to -1\n  if ((id = findsymbol(Text)) != -1)\n    if (Symtable[id].stype != S_FUNCTION)\n      id = -1;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (id == -1) {\n    endlabel = genlabel();\n    nameslot = addglob(Text, type, S_FUNCTION, C_GLOBAL, endlabel, 0);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype symbol slot number\n  lparen();\n  paramcnt = param_declaration(id);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters\n  if (id == -1)\n    Symtable[nameslot].nelems = paramcnt;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n  // This is not just a prototype.\n  // Copy the global parameters to be local parameters\n  if (id == -1)\n    id = nameslot;\n  copyfuncparams(id);\n\n  // Set the Functionid global to the function's symbol-id\n  Functionid = id;\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's id\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, id));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration\n      tree = function_declaration(type);\n\n      // Only a function prototype, no code\n      if (tree == NULL)\n\tcontinue;\n\n      // A real function, generate the assembly code for it\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, C_GLOBAL);\n      semi();\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "26_Prototypes/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(int id);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id, int op);\nint cgloadlocal(int id, int op);\nint cgloadglobstr(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(int id, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, int id);\nint cgstorlocal(int r, int id);\nvoid cgglobsym(int id);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint findlocl(char *s);\nint findsymbol(char *s);\nint addglob(char *name, int type, int stype, int class, int endlabel, int size);\nint addlocl(char *name, int type, int stype, int class, int size);\nvoid copyfuncparams(int slot);\nvoid freeloclsyms(void);\n\n// decl.c\nvoid var_declaration(int type, int class);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint parse_type(void);\nint pointer_to(int type);\nint value_at(int type);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "26_Prototypes/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND, \n  T_OR, T_XOR, T_AMPER, \n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN= 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n#define NOLABEL\t 0\t\t// Use NOLABEL when we have no label to\n\t\t\t\t// pass to genAST()\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n        C_GLOBAL = 1,\t\t// Globally visible symbol\n        C_LOCAL,\t\t// Locally visible symbol\n        C_PARAM\t\t\t// Locally visible function parameter\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n  int size;\t\t\t// Number of elements in the symbol\n  int posn;\t\t\t// For locals, either the negative offset\n\t\t\t\t// from stack base pointer, or register id\n#define nelems posn\t\t// For functions, # of params\n\t\t\t\t// For structs, # of fields\n};\n"
  },
  {
    "path": "26_Prototypes/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Symtable[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  int id;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, Symtable[id].type, id);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, Symtable[id].type, left, NULL, right, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  int id;\n\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // A variable. Check that the variable exists.\n  id = findsymbol(Text);\n  if (id == -1 || Symtable[id].stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, Symtable[id].type, id);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, Symtable[id].type, id);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, Symtable[id].type, id);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, P_CHARPTR, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (left == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(binastop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "26_Prototypes/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->v.size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->v.size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->v.id, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n  case A_IF:\n    return (genIF(n));\n  case A_WHILE:\n    return (genWHILE(n));\n  case A_FUNCCALL:\n    return (gen_funccall(n));\n  case A_GLUE:\n    // Do each child statement, and free the\n    // registers after each child\n    genAST(n->left, NOLABEL, n->op);\n    genfreeregs();\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    return (NOREG);\n  case A_FUNCTION:\n    // Generate the function's preamble before the code\n    // in the child sub-tree\n    cgfuncpreamble(n->v.id);\n    genAST(n->left, NOLABEL, n->op);\n    cgfuncpostamble(n->v.id);\n    return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n  case A_ADD:\n    return (cgadd(leftreg, rightreg));\n  case A_SUBTRACT:\n    return (cgsub(leftreg, rightreg));\n  case A_MULTIPLY:\n    return (cgmul(leftreg, rightreg));\n  case A_DIVIDE:\n    return (cgdiv(leftreg, rightreg));\n  case A_AND:\n    return (cgand(leftreg, rightreg));\n  case A_OR:\n    return (cgor(leftreg, rightreg));\n  case A_XOR:\n    return (cgxor(leftreg, rightreg));\n  case A_LSHIFT:\n    return (cgshl(leftreg, rightreg));\n  case A_RSHIFT:\n    return (cgshr(leftreg, rightreg));\n  case A_EQ:\n  case A_NE:\n  case A_LT:\n  case A_GT:\n  case A_LE:\n  case A_GE:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, compare registers\n    // and set one to 1 or 0 based on the comparison.\n    if (parentASTop == A_IF || parentASTop == A_WHILE)\n      return (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n    else\n      return (cgcompare_and_set(n->op, leftreg, rightreg));\n  case A_INTLIT:\n    return (cgloadint(n->v.intvalue, n->type));\n  case A_STRLIT:\n    return (cgloadglobstr(n->v.id));\n  case A_IDENT:\n    // Load our value if we are an rvalue\n    // or we are being dereferenced\n    if (n->rvalue || parentASTop == A_DEREF) {\n      if (Symtable[n->v.id].class == C_GLOBAL) {\n\treturn (cgloadglob(n->v.id, n->op));\n      } else {\n\treturn (cgloadlocal(n->v.id, n->op));\n      }\n    } else\n      return (NOREG);\n  case A_ASSIGN:\n    // Are we assigning to an identifier or through a pointer?\n    switch (n->right->op) {\n    case A_IDENT:\n      if (Symtable[n->right->v.id].class == C_GLOBAL)\n\treturn (cgstorglob(leftreg, n->right->v.id));\n      else\n\treturn (cgstorlocal(leftreg, n->right->v.id));\n    case A_DEREF:\n      return (cgstorderef(leftreg, rightreg, n->right->type));\n    default:\n      fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n    }\n  case A_WIDEN:\n    // Widen the child's type to the parent's type\n    return (cgwiden(leftreg, n->left->type, n->type));\n  case A_RETURN:\n    cgreturn(leftreg, Functionid);\n    return (NOREG);\n  case A_ADDR:\n    return (cgaddress(n->v.id));\n  case A_DEREF:\n    // If we are an rvalue, dereference to get the value we point at,\n    // otherwise leave it for A_ASSIGN to store through the pointer\n    if (n->rvalue)\n      return (cgderef(leftreg, n->left->type));\n    else\n      return (leftreg);\n  case A_SCALE:\n    // Small optimisation: use shift if the\n    // scale value is a known power of two\n    switch (n->v.size) {\n    case 2:\n      return (cgshlconst(leftreg, 1));\n    case 4:\n      return (cgshlconst(leftreg, 2));\n    case 8:\n      return (cgshlconst(leftreg, 3));\n    default:\n      // Load a register with the size and\n      // multiply the leftreg by this size\n      rightreg = cgloadint(n->v.size, P_INT);\n      return (cgmul(leftreg, rightreg));\n    }\n  case A_POSTINC:\n    // Load the variable's value into a register,\n    // then increment it\n    return (cgloadglob(n->v.id, n->op));\n  case A_POSTDEC:\n    // Load the variable's value into a register,\n    // then decrement it\n    return (cgloadglob(n->v.id, n->op));\n  case A_PREINC:\n    // Load and increment the variable's value into a register\n    return (cgloadglob(n->left->v.id, n->op));\n  case A_PREDEC:\n    // Load and decrement the variable's value into a register\n    return (cgloadglob(n->left->v.id, n->op));\n  case A_NEGATE:\n    return (cgnegate(leftreg));\n  case A_INVERT:\n    return (cginvert(leftreg));\n  case A_LOGNOT:\n    return (cglognot(leftreg));\n  case A_TOBOOL:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, set the register\n    // to 0 or 1 based on it's zeroeness or non-zeroeness\n    return (cgboolean(leftreg, parentASTop, label));\n  default:\n    fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "26_Prototypes/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n\nvoid printchar(long x) {\n  putc((char)(x & 0x7f), stdout);\n}\n"
  },
  {
    "path": "26_Prototypes/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n  Globs = 0;\n  Locls = NSYMBOLS - 1;\n  O_dumpAST = 0;\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-T] infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nint main(int argc, char *argv[]) {\n  int i;\n\n  // Initialise the globals\n  init();\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    if (*argv[i] != '-')\n      break;\n    for (int j = 1; argv[i][j]; j++) {\n      switch (argv[i][j]) {\n      case 'T':\n\tO_dumpAST = 1;\n\tbreak;\n      default:\n\tusage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have an input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Open up the input file\n  if ((Infile = fopen(argv[i], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[i], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n  // For now, ensure that printint() and printchar() are defined\n  addglob(\"printint\", P_INT, S_FUNCTION, C_GLOBAL, 0, 0);\n  addglob(\"printchar\", P_VOID, S_FUNCTION, C_GLOBAL, 0, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  return (0);\n}\n"
  },
  {
    "path": "26_Prototypes/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "26_Prototypes/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n    case 'a':\n      return '\\a';\n    case 'b':\n      return '\\b';\n    case 'f':\n      return '\\f';\n    case 'n':\n      return '\\n';\n    case 'r':\n      return '\\r';\n    case 't':\n      return '\\t';\n    case 'v':\n      return '\\v';\n    case '\\\\':\n      return '\\\\';\n    case '\"':\n      return '\"';\n    case '\\'':\n      return '\\'';\n    default:\n      fatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n  case 'c':\n    if (!strcmp(s, \"char\"))\n      return (T_CHAR);\n    break;\n  case 'e':\n    if (!strcmp(s, \"else\"))\n      return (T_ELSE);\n    break;\n  case 'f':\n    if (!strcmp(s, \"for\"))\n      return (T_FOR);\n    break;\n  case 'i':\n    if (!strcmp(s, \"if\"))\n      return (T_IF);\n    if (!strcmp(s, \"int\"))\n      return (T_INT);\n    break;\n  case 'l':\n    if (!strcmp(s, \"long\"))\n      return (T_LONG);\n    break;\n  case 'r':\n    if (!strcmp(s, \"return\"))\n      return (T_RETURN);\n    break;\n  case 'w':\n    if (!strcmp(s, \"while\"))\n      return (T_WHILE);\n    break;\n  case 'v':\n    if (!strcmp(s, \"void\"))\n      return (T_VOID);\n    break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n  case EOF:\n    t->token = T_EOF;\n    return (0);\n  case '+':\n    if ((c = next()) == '+') {\n      t->token = T_INC;\n    } else {\n      putback(c);\n      t->token = T_PLUS;\n    }\n    break;\n  case '-':\n    if ((c = next()) == '-') {\n      t->token = T_DEC;\n    } else {\n      putback(c);\n      t->token = T_MINUS;\n    }\n    break;\n  case '*':\n    t->token = T_STAR;\n    break;\n  case '/':\n    t->token = T_SLASH;\n    break;\n  case ';':\n    t->token = T_SEMI;\n    break;\n  case '{':\n    t->token = T_LBRACE;\n    break;\n  case '}':\n    t->token = T_RBRACE;\n    break;\n  case '(':\n    t->token = T_LPAREN;\n    break;\n  case ')':\n    t->token = T_RPAREN;\n    break;\n  case '[':\n    t->token = T_LBRACKET;\n    break;\n  case ']':\n    t->token = T_RBRACKET;\n    break;\n  case '~':\n    t->token = T_INVERT;\n    break;\n  case '^':\n    t->token = T_XOR;\n    break;\n  case ',':\n    t->token = T_COMMA;\n    break;\n  case '=':\n    if ((c = next()) == '=') {\n      t->token = T_EQ;\n    } else {\n      putback(c);\n      t->token = T_ASSIGN;\n    }\n    break;\n  case '!':\n    if ((c = next()) == '=') {\n      t->token = T_NE;\n    } else {\n      putback(c);\n      t->token = T_LOGNOT;\n    }\n    break;\n  case '<':\n    if ((c = next()) == '=') {\n      t->token = T_LE;\n    } else if (c == '<') {\n      t->token = T_LSHIFT;\n    } else {\n      putback(c);\n      t->token = T_LT;\n    }\n    break;\n  case '>':\n    if ((c = next()) == '=') {\n      t->token = T_GE;\n    } else if (c == '>') {\n      t->token = T_RSHIFT;\n    } else {\n      putback(c);\n      t->token = T_GT;\n    }\n    break;\n  case '&':\n    if ((c = next()) == '&') {\n      t->token = T_LOGAND;\n    } else {\n      putback(c);\n      t->token = T_AMPER;\n    }\n    break;\n  case '|':\n    if ((c = next()) == '|') {\n      t->token = T_LOGOR;\n    } else {\n      putback(c);\n      t->token = T_OR;\n    }\n    break;\n  case '\\'':\n    // If it's a quote, scan in the\n    // literal character value and\n    // the trailing quote\n    t->intvalue = scanch();\n    t->token = T_INTLIT;\n    if (next() != '\\'')\n      fatal(\"Expected '\\\\'' at end of char literal\");\n    break;\n  case '\"':\n    // Scan in a literal string\n    scanstr(Text);\n    t->token = T_STRLIT;\n    break;\n  default:\n    // If it's a digit, scan the\n    // literal integer value in\n    if (isdigit(c)) {\n      t->intvalue = scanint(c);\n      t->token = T_INTLIT;\n      break;\n    } else if (isalpha(c) || '_' == c) {\n      // Read in a keyword or identifier\n      scanident(c, Text, TEXTLEN);\n\n      // If it's a recognised keyword, return that token\n      if ((tokentype = keyword(Text)) != 0) {\n\tt->token = tokentype;\n\tbreak;\n      }\n      // Not a recognised keyword, so it must be an identifier\n      t->token = T_IDENT;\n      break;\n    }\n    // The character isn't part of any recognised token, error\n    fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "26_Prototypes/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Symtable[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Symtable[Functionid].type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n\n    // The beginning of a variable declaration.\n    // Parse the type and get the identifier.\n    // Then parse the rest of the declaration\n    // and skip over the semicolon\n    type = parse_type();\n    ident();\n    var_declaration(type, C_LOCAL);\n    semi();\n    return (NULL);\t\t// No AST generated here\n  case T_IF:\n    return (if_statement());\n  case T_WHILE:\n    return (while_statement());\n  case T_FOR:\n    return (for_statement());\n  case T_RETURN:\n    return (return_statement());\n  default:\n    // For now, see if this is an expression.\n    // This catches assignment statements.\n    return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "26_Prototypes/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\n// Skip C_PARAM entries\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (Symtable[i].class == C_PARAM)\n      continue;\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= Locls)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return its slot position or -1 if not found.\nint findlocl(char *s) {\n  int i;\n\n  for (i = Locls + 1; i < NSYMBOLS; i++) {\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new local symbol slot, or die\n// if we've run out of positions.\nstatic int newlocl(void) {\n  int p;\n\n  if ((p = Locls--) <= Globs)\n    fatal(\"Too many local symbols\");\n  return (p);\n}\n\n// Clear all the entries in the\n// local symbol table\nvoid freeloclsyms(void) {\n  Locls = NSYMBOLS - 1;\n}\n\n// Update a symbol at the given slot number in the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + endlabel: if this is a function\n// + posn: Position information for local symbols\nstatic void updatesym(int slot, char *name, int type, int stype,\n\t\t      int class, int endlabel, int size, int posn) {\n  if (slot < 0 || slot >= NSYMBOLS)\n    fatal(\"Invalid symbol slot number in updatesym()\");\n  Symtable[slot].name = strdup(name);\n  Symtable[slot].type = type;\n  Symtable[slot].stype = stype;\n  Symtable[slot].class = class;\n  Symtable[slot].endlabel = endlabel;\n  Symtable[slot].size = size;\n  Symtable[slot].posn = posn;\n}\n\n// Add a global symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + class of the symbol\n// + size: number of elements\n// + endlabel: if this is a function\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int class, int endlabel,\n\t    int size) {\n  int slot;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((slot = findglob(name)) != -1)\n    return (slot);\n\n  // Otherwise get a new slot and fill it in\n  slot = newglob();\n  updatesym(slot, name, type, stype, class, endlabel, size, 0);\n  // Generate the assembly for the symbol if it's global\n  if (class == C_GLOBAL)\n    genglobsym(slot);\n  // Return the slot number\n  return (slot);\n}\n\n// Add a local symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// Return the slot number in the symbol table, -1 if a duplicate entry\nint addlocl(char *name, int type, int stype, int class, int size) {\n  int localslot;\n\n  // If this is already in the symbol table, return an error\n  if ((localslot = findlocl(name)) != -1)\n    return (-1);\n\n  // Otherwise get a new symbol slot and a position for this local.\n  // Update the local symbol table entry.\n  localslot = newlocl();\n  updatesym(localslot, name, type, stype, class, 0, size, 0);\n\n  // Return the local symbol's slot\n  return (localslot);\n}\n\n// Given a function's slot number, copy the global parameters\n// from its prototype to be local parameters\nvoid copyfuncparams(int slot) {\n  int i, id = slot + 1;\n\n  for (i = 0; i < Symtable[slot].nelems; i++, id++) {\n    addlocl(Symtable[id].name, Symtable[id].type, Symtable[id].stype,\n\t    Symtable[id].class, Symtable[id].size);\n  }\n}\n\n\n// Determine if the symbol s is in the symbol table.\n// Return its slot position or -1 if not found.\nint findsymbol(char *s) {\n  int slot;\n\n  slot = findlocl(s);\n  if (slot == -1)\n    slot = findglob(s);\n  return (slot);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input01.c",
    "content": "void main()\n{ printint(12 * 3);\n  printint(18 - 2 * 4);\n  printint(1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input02.c",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printint(fred + jim);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input03.c",
    "content": "void main()\n{\n  int x;\n  x= 1;     printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input04.c",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  printint(x);\n  x= 7 <= 9; printint(x);\n  x= 7 != 9; printint(x);\n  x= 7 == 7; printint(x);\n  x= 7 >= 7; printint(x);\n  x= 7 <= 7; printint(x);\n  x= 9 > 7;  printint(x);\n  x= 9 >= 7; printint(x);\n  x= 9 != 7; printint(x);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input05.c",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printint(i);\n  } else {\n    printint(j);\n  }\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input06.c",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printint(i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input07.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input08.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input09.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printint(2 * b - a); }\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input10.c",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; printint(j);\n  i= 10; printint(i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 2; j= j + 1) { printint(j); }\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input11.c",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; printint(i);\n  j= 20; printint(j);\n  k= 30; printint(k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 4; j= j + 1) { printint(j); }\n  for (k= 1;   k <= 5; k= k + 1) { printint(k); }\n  return(i);\n  printint(12345);\n  return(3);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input12.c",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printint(x);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input13.c",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input14.c",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input15.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printint(a);\n  b= &a; c= *b; printint(c);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input16.c",
    "content": "int   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printint(c);\n  e= &c + 1; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input17.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printint(a);\n  e= &d; *e= 12; printint(d);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input18.c",
    "content": "int main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printint(a);\n  printint(b);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input18a.c",
    "content": "int   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printint(a);\n  d= &c; *d= 16; printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input19.c",
    "content": "int a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printint(e);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input20.c",
    "content": "int a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printint(a);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input21.c",
    "content": "char  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printint(c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printchar(*str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input22.c",
    "content": "char a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printint(a);\n  e= 5; f= 7; d= e + f++; printint(d);\n  h= 5; i= 7; g= h + i++; printint(g);\n  a= b-- + c; printint(a);\n  d= e-- + f; printint(d);\n  g= h-- + i; printint(g);\n  a= ++b + c; printint(a);\n  d= ++e + f; printint(d);\n  g= ++h + i; printint(g);\n  a= b * --c; printint(a);\n  d= e * --f; printint(d);\n  g= h * --i; printint(g);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input23.c",
    "content": "char *str;\nint   x;\n\nint main() {\n  x= -23; printint(x);\n  printint(-10 * -10);\n\n  x= 1; x= ~x; printint(x);\n\n  x= 2 > 5; printint(x);\n  x= !x; printint(x);\n  x= !x; printint(x);\n\n  x= 13; if (x) { printint(13); }\n  x= 0; if (!x) { printint(14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printchar(*str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input24.c",
    "content": "int a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printint(a & b);\n  printint(a | b);\n  printint(a ^ b);\n  printint(1 << 3);\n  printint(63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input25.c",
    "content": "int a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printint(x); printint(y); printint(z);\n  a= 5; b= 15; c= 25;\n  printint(a); printint(b); printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input26.c",
    "content": "int main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printint(a);\n  b= 23; printint(b);\n  c= 34; printint(c);\n  d= 44; printint(d);\n  e= 54; printint(e);\n  f= 64; printint(f);\n  g= 74; printint(g);\n  h= 84; printint(h);\n  i= 94; printint(i);\n  j= 95; printint(j);\n  k= 96; printint(k);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input27.c",
    "content": "int param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printint(a); printint(b); printint(c); printint(d);\n  printint(e); printint(f); printint(g); printint(h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input28.c",
    "content": "int param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printint(a); printint(b); printint(c); printint(d);\n  printint(e); printint(f); printint(g); printint(h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printint(x);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input29.c",
    "content": "int param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printint(a); printint(b); printint(c); printint(d);\n  printint(e); printint(f); printint(g); printint(h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printint(x);\n  return(0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/input30.c",
    "content": "int open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" ]\n   then\n     cc -o out $i ../lib/printint.c\n     ./out > out.$i\n     rm -f out\n   fi\ndone\n"
  },
  {
    "path": "26_Prototypes/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "26_Prototypes/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "26_Prototypes/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "26_Prototypes/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "26_Prototypes/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "26_Prototypes/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "26_Prototypes/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "26_Prototypes/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "26_Prototypes/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "26_Prototypes/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "26_Prototypes/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "26_Prototypes/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "26_Prototypes/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "26_Prototypes/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "26_Prototypes/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "26_Prototypes/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "26_Prototypes/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "26_Prototypes/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "26_Prototypes/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "26_Prototypes/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "26_Prototypes/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "26_Prototypes/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "26_Prototypes/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "26_Prototypes/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "26_Prototypes/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "26_Prototypes/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "26_Prototypes/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "26_Prototypes/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "26_Prototypes/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "26_Prototypes/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "26_Prototypes/tests/out.input30.c",
    "content": "int open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "26_Prototypes/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../comp1 ]\nthen echo \"Need to build ../comp1 first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../comp1 $i\n     cc -o out out.s ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "26_Prototypes/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\nif [ ! -f ../compn ]\nthen echo \"Need to build ../compn first!\"; exit 1\nfi\n\nfor i in input*\ndo if [ ! -f \"out.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n   else\n     echo -n $i\n     ../compn $i\n     nasm -f elf64 out.s\n     cc -no-pie -fno-plt -Wall -o out out.o ../lib/printint.c\n     ./out > trial.$i\n     cmp -s \"out.$i\" \"trial.$i\"\n     if [ \"$?\" -eq \"1\" ]\n     then echo \": failed\"\n       diff -c \"out.$i\" \"trial.$i\"\n       echo\n     else echo \": OK\"\n     fi\n     rm -f out out.o out.s \"trial.$i\"\n   fi\ndone\n"
  },
  {
    "path": "26_Prototypes/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n  case A_IF:\n    Lfalse = gendumplabel();\n    for (int i = 0; i < level; i++)\n      fprintf(stdout, \" \");\n    fprintf(stdout, \"A_IF\");\n    if (n->right) {\n      Lend = gendumplabel();\n      fprintf(stdout, \", end L%d\", Lend);\n    }\n    fprintf(stdout, \"\\n\");\n    dumpAST(n->left, Lfalse, level + 2);\n    dumpAST(n->mid, NOLABEL, level + 2);\n    if (n->right)\n      dumpAST(n->right, NOLABEL, level + 2);\n    return;\n  case A_WHILE:\n    Lstart = gendumplabel();\n    for (int i = 0; i < level; i++)\n      fprintf(stdout, \" \");\n    fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n    Lend = gendumplabel();\n    dumpAST(n->left, Lend, level + 2);\n    dumpAST(n->right, NOLABEL, level + 2);\n    return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n  case A_GLUE:\n    fprintf(stdout, \"\\n\\n\");\n    return;\n  case A_FUNCTION:\n    fprintf(stdout, \"A_FUNCTION %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_ADD:\n    fprintf(stdout, \"A_ADD\\n\");\n    return;\n  case A_SUBTRACT:\n    fprintf(stdout, \"A_SUBTRACT\\n\");\n    return;\n  case A_MULTIPLY:\n    fprintf(stdout, \"A_MULTIPLY\\n\");\n    return;\n  case A_DIVIDE:\n    fprintf(stdout, \"A_DIVIDE\\n\");\n    return;\n  case A_EQ:\n    fprintf(stdout, \"A_EQ\\n\");\n    return;\n  case A_NE:\n    fprintf(stdout, \"A_NE\\n\");\n    return;\n  case A_LT:\n    fprintf(stdout, \"A_LE\\n\");\n    return;\n  case A_GT:\n    fprintf(stdout, \"A_GT\\n\");\n    return;\n  case A_LE:\n    fprintf(stdout, \"A_LE\\n\");\n    return;\n  case A_GE:\n    fprintf(stdout, \"A_GE\\n\");\n    return;\n  case A_INTLIT:\n    fprintf(stdout, \"A_INTLIT %d\\n\", n->v.intvalue);\n    return;\n  case A_STRLIT:\n    fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->v.id);\n    return;\n  case A_IDENT:\n    if (n->rvalue)\n      fprintf(stdout, \"A_IDENT rval %s\\n\", Symtable[n->v.id].name);\n    else\n      fprintf(stdout, \"A_IDENT %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_ASSIGN:\n    fprintf(stdout, \"A_ASSIGN\\n\");\n    return;\n  case A_WIDEN:\n    fprintf(stdout, \"A_WIDEN\\n\");\n    return;\n  case A_RETURN:\n    fprintf(stdout, \"A_RETURN\\n\");\n    return;\n  case A_FUNCCALL:\n    fprintf(stdout, \"A_FUNCCALL %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_ADDR:\n    fprintf(stdout, \"A_ADDR %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_DEREF:\n    if (n->rvalue)\n      fprintf(stdout, \"A_DEREF rval\\n\");\n    else\n      fprintf(stdout, \"A_DEREF\\n\");\n    return;\n  case A_SCALE:\n    fprintf(stdout, \"A_SCALE %d\\n\", n->v.size);\n    return;\n  case A_PREINC:\n    fprintf(stdout, \"A_PREINC %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_PREDEC:\n    fprintf(stdout, \"A_PREDEC %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_POSTINC:\n    fprintf(stdout, \"A_POSTINC\\n\");\n    return;\n  case A_POSTDEC:\n    fprintf(stdout, \"A_POSTDEC\\n\");\n    return;\n  case A_NEGATE:\n    fprintf(stdout, \"A_NEGATE\\n\");\n    return;\n  default:\n    fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "26_Prototypes/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  if (type == P_CHAR || type == P_INT || type == P_LONG)\n    return (1);\n  return (0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  if (type == P_VOIDPTR || type == P_CHARPTR ||\n      type == P_INTPTR || type == P_LONGPTR)\n    return (1);\n  return (0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n  case P_VOID:\n    newtype = P_VOIDPTR;\n    break;\n  case P_CHAR:\n    newtype = P_CHARPTR;\n    break;\n  case P_INT:\n    newtype = P_INTPTR;\n    break;\n  case P_LONG:\n    newtype = P_LONGPTR;\n    break;\n  default:\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n  case P_VOIDPTR:\n    newtype = P_VOID;\n    break;\n  case P_CHARPTR:\n    newtype = P_CHAR;\n    break;\n  case P_INTPTR:\n    newtype = P_INT;\n    break;\n  case P_LONGPTR:\n    newtype = P_LONG;\n    break;\n  default:\n    fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "27_Testing_Errors/Makefile",
    "content": "HSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncomp1: $(SRCS) $(HSRCS)\n\tcc -o comp1 -g -Wall $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -o compn -g -Wall $(SRCN)\n\ncomp1arm: $(ARMSRCS) $(HSRCS)\n\tcc -o comp1arm -g -Wall $(ARMSRCS)\n\tcp comp1arm comp1\n\nclean:\n\trm -f comp1 comp1arm compn *.o *.s out\n\ntest: comp1 tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: comp1arm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "27_Testing_Errors/Readme.md",
    "content": "# Part 27: Regression Testing and a Nice Surprise\n\nWe've had a few large-ish steps recently in our \ncompiler writing journey, so I thought we should have\na bit of a breather in this step. We can slow down a\nbit and review our progress so far.\n\nIn the last step I noticed that we didn't have a way to\nconfirm that our syntax and semantic error checking was\nworking correctly. So I've just rewritten the scripts\nin the `tests/` folder to do this.\n\nI've been using Unix since the late 1980s, so my go-to\nautomation tools are shell scripts and Makefiles or,\nif I need more complex tools, scripts written in Python\nor Perl (yes, I'm that old).\n\nSo let's quickly look at the `runtest` script in the\n`tests/` directory. Even though I said I'd been using\nUnix scripts forever, I'm definitely not an uber\nscript writer.\n\n## The `runtest` Script\n\nThe job of this script is to take a set of input programs,\nget our compiler to compile them, run the executable\nand compare its output against known-good output. If they\nmatch, the test is a success. If not, it's a failure.\n\nI've just extended it so that, if there is an \"error\"\nfile associated with an input, we run our compiler\nand capture its error output. If this error output\nmatches the expected error output, the test is a\nsuccess as the compiler correctly detected the bad input.\n\nSo let's look at the sections of the `runtest` script in stages.\n\n```\n# Build our compiler if needed\nif [ ! -f ../comp1 ]\nthen (cd ..; make)\nfi\n```\n\nI'm using the '( ... )' syntax here to create a *sub-shell*. This\ncan change its working directory without affecting the original\nshell, so we can move up a directory and rebuild our compiler.\n\n\n```\n# Try to use each input source file\nfor i in input*\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n```\n\nThe '[' thing is actually the external Unix tool, *test(1)*.\nOh, if you've never seen this syntax before, *test(1)* means\nthe manual page for *test* is in Section One of the man pages,\nand you can do:\n\n```\n$ man 1 test\n```\n\nto read the manual for *test* in Section One of the man pages.\nThe `/usr/bin/[` executable is usually linked to `/usr/bin/test`,\nso that when you use '[' in a shell script, it's the same as running\nthe *test* command.\n\nWe can read the line `[ ! -f \"out.$i\" -a ! -f \"err.$i\" ]` as saying:\ntest if there is no file \"out.$i\" and no file \"err.$i\". If both\ndon't exist, we can give the error message.\n\n```\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n          # Print the test name, compile it\n          # with our compiler\n          echo -n $i\n          ../comp1 $i\n\n          # Assemble the output, run it\n          # and get the output in trial.$i\n          cc -o out out.s ../lib/printint.c\n          ./out > trial.$i\n\n          # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n          # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n          # No failure, so announce success\n          else echo \": OK\"\n          fi\n```\n\nThis is the bulk of the script. I think the comments\nexplain what is going on, but perhaps there are some\nsubtleties to flesh out. `cmp -s` compares two\ntext files;  the `-s` flag means produce no output\nbut set the exit value that `cmp` gives when it exits to:\n\n> 0 if inputs are the same, 1  if  different,  2  if\n  trouble. (from the man page)\n\nThe line `if [ \"$?\" -eq \"1\" ]` says: if the exit value\nof the last command is equal to the number 1. So, if\nthe compiler's output is different to the known-good\noutput, we announce this and use the `diff` tool to\nshow the differences between the two files.\n\n```\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../comp1 $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          ...\n```\n\nThis section gets executed when there is an error\ndocument, \"err.$i\". This time, we use the shell\nsyntax `2>` to capture our compiler's standard\nerror output to the file \"trial.$i\" and compare\nthat against the correct error output. The logic\nafter this is the same as before.\n\n## What We Are Doing: Regression Testing\n\nI haven't talked much before about testing, but now's the\ntime. I've taught software development in the past so it\nwould be remiss of me not to cover testing at some point.\n\nWhat we are doing here is [**regression testing**](https://en.wikipedia.org/wiki/Regression_testing).\nWikipedia gives this definition:\n\n> Regression testing is the action of re-running functional and non-functional tests\n> to ensure that previously developed and tested software still performs after a change.\n\nAs our compiler is changing at each step, we have to ensure that each new change doesn't\nbreak the functionality (and the error checking) of the previous steps. So each time I\nintroduce a change, I add one or more tests to a) prove that it works and b) re-run\nthis test on future changes. As long as all the tests pass, I'm sure that the new\ncode hasn't broken the old code.\n\n### Functional Tests\n\nThe `runtests` script looks for files with the `out` prefix to do the\nfunctional testing. Right now, we have:\n\n```\ntests/out.input01.c  tests/out.input12.c   tests/out.input22.c\ntests/out.input02.c  tests/out.input13.c   tests/out.input23.c\ntests/out.input03.c  tests/out.input14.c   tests/out.input24.c\ntests/out.input04.c  tests/out.input15.c   tests/out.input25.c\ntests/out.input05.c  tests/out.input16.c   tests/out.input26.c\ntests/out.input06.c  tests/out.input17.c   tests/out.input27.c\ntests/out.input07.c  tests/out.input18a.c  tests/out.input28.c\ntests/out.input08.c  tests/out.input18.c   tests/out.input29.c\ntests/out.input09.c  tests/out.input19.c   tests/out.input30.c\ntests/out.input10.c  tests/out.input20.c   tests/out.input53.c\ntests/out.input11.c  tests/out.input21.c   tests/out.input54.c\n```\n\nThat's 33 separate tests of the compiler's functionality. Right now,\nI know for a fact that our compiler is a bit fragile. None of these\ntests really stress the compiler in any way: they are simple tests\nof a few lines each. Later on, we will start to add some nasty stress\ntests to help strengthen the compiler and make it more resilient.\n\n### Non-Functional Tests\n\nThe `runtests` script looks for files with the `err` prefix to do the\nfunctional testing. Right now, we have:\n\n```\ntests/err.input31.c  tests/err.input39.c  tests/err.input47.c\ntests/err.input32.c  tests/err.input40.c  tests/err.input48.c\ntests/err.input33.c  tests/err.input41.c  tests/err.input49.c\ntests/err.input34.c  tests/err.input42.c  tests/err.input50.c\ntests/err.input35.c  tests/err.input43.c  tests/err.input51.c\ntests/err.input36.c  tests/err.input44.c  tests/err.input52.c\ntests/err.input37.c  tests/err.input45.c\ntests/err.input38.c  tests/err.input46.c\n```\n\nI created these 22 tests of the compiler's error checking in this\nstep of our journey by looking for `fatal()` calls in the compiler.\nFor each one, I've tried to write a small input file which would\ntrigger it. Have a read of the matching source files and see if\nyou can work out what syntax or semantic error each one triggers.\n\n## Other Forms of Testing\n\nThis isn't a course on software development methodologies, so I won't give\ntoo much more coverage on testing. But I'll give you links to a few\nmore thing that I would highly recommend that you look at:\n\n  + [Unit testing](https://en.wikipedia.org/wiki/Unit_testing)\n  + [Test-driven development](https://en.wikipedia.org/wiki/Test-driven_development)\n  + [Continuous integration](https://en.wikipedia.org/wiki/Continuous_integration)\n  + [Version control](https://en.wikipedia.org/wiki/Version_control)\n\nI haven't done any unit testing with our compiler. The main reason\nhere is that the code is very fluid in terms of the APIs for the\nfunctions. I'm not using a traditional waterfall model of development,\nso I'd be spending too much time rewriting my unit tests to match\nthe latest APIs of all the functions. So, in some sense I am living\ndangerously here: there will be a number of latent bugs in the code\nwhich we haven't detected yet.\n\nHowever, there are guaranteed to be *many* more bugs where the\ncompiler looks like it accepts the C language, but of course this isn't\ntrue. The compiler is failing the\n[principle of least astonishment](https://en.wikipedia.org/wiki/Principle_of_least_astonishment). We will need to spend some time adding in\nfunctionality that a \"normal\" C programmer expects to see.\n\n## And a Nice Surprise\n\nFinally, we have a nice functional surprise with the compiler as it\nstands. A while back, I purposefully left out the code to test\nthat the number and type of arguments to a function call matches\nthe function's prototype (in `expr.c`):\n\n```\n  // XXX Check type of each argument against the function's prototype\n```\n\nI left this out as I didn't want to add too much new code in one of\nour steps.\n\nNow that we have prototypes, I've wanted to finally add support for\n`printf()` so that we can ditch our homegrown `printint()` and\n`printchar()` functions. But we can't do this just yet, because\n`printf()` is a [variadic function](https://en.wikipedia.org/wiki/Variadic_function):\nit can accept a variable number of parameters. And, right now, our\ncompiler only allows a function declaration with a fixed number of\nparameters.\n\n*However* (and this is the nice surprise), because we don't check\nthe number of arguments in a function call, we can pass *any* number\nof arguments to `printf()` as long as we have given it an existing\nprototype. So, at present, this code (`tests/input53.c`) works:\n\n```c\nint printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n```\n\nAnd that's a nice thing!\n\nThere is a gotcha. With the given `printf()` prototype, the cleanup code\nin `cgcall()` won't adjust the stack pointer when the function returns,\nas there are less than six parameters in the prototype. But we could\ncall `printf()` with ten arguments: we'd push four of them on the stack,\nbut `cgcall()` wouldn't clean up these four arguments when `printf()`\nreturns.\n\n## Conclusion and What's Next\n\nThere is no new compiler code in this step, but we are now testing the\nerror checking capability of the compiler, and we now have 54\nregression tests to help ensure we don't break the compiler when\nwe add new functionality. And, fortuitously, we can now use\n`printf()` as well as the other external fixed parameter count functions.\n\nIn the next part of our compiler writing journey, I think I'll\ntry to:\n\n + add support for an external pre-processor\n + allow the compiler to compile multiple files named on the command line\n + add the `-o`, `-c` and `-S` flags to the compiler to make it feel\nmore like a \"normal\" C compiler [Next step](../28_Runtime_Flags/Readme.md)\n"
  },
  {
    "path": "27_Testing_Errors/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  int i;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack\n  // Stop after no more than six parameter registers\n  for (i = NSYMBOLS - 1; i > Locls; i--) {\n    if (Symtable[i].class != C_PARAM)\n      break;\n    if (i < NSYMBOLS - 6)\n      break;\n    Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    cgstorlocal(paramReg--, i);\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (; i > Locls; i--) {\n    if (Symtable[i].class == C_PARAM) {\n      Symtable[i].posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    }\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n    break;\n  case P_INT:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    break;\n  case P_INT:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    break;\n  default:\n    fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", id, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(int id, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", Symtable[id].name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r],\n\t    Symtable[id].name);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r],\n\t    Symtable[id].name);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r],\n\t    Symtable[id].name);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r],\n\t    Symtable[id].posn);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r],\n\t    Symtable[id].posn);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r],\n\t    Symtable[id].posn);\n    break;\n  default:\n    fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n    break;\n  case P_LONG:\n    fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n    break;\n  default:\n    fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_LOCAL)\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n    fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  default:\n    fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  case P_LONG:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "27_Testing_Errors/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4, 4, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n  case 1:\n    fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n    break;\n  case 4:\n    fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n    break;\n  default:\n    fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n    break;\n  case P_INT:\n  case P_LONG:\n    fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "27_Testing_Errors/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  int i;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack\n  // Stop after no more than six parameter registers\n  for (i = NSYMBOLS - 1; i > Locls; i--) {\n    if (Symtable[i].class != C_PARAM)\n      break;\n    if (i < NSYMBOLS - 6)\n      break;\n    Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    cgstorlocal(paramReg--, i);\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (; i > Locls; i--) {\n    if (Symtable[i].class == C_PARAM) {\n      Symtable[i].posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    }\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Symtable[id].name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              Symtable[id].name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Symtable[id].name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              Symtable[id].posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n              Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n              Symtable[id].posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], id);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(int id, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Symtable[id].name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  // original version\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch(typesize) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(typesize) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", Symtable[id].size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", Symtable[id].size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", Symtable[id].size);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_LOCAL)\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            Symtable[id].posn);\n  else\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Symtable[id].name);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "27_Testing_Errors/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ int Locls;\t\t// Position of next free local symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Symtable[NSYMBOLS];\t// Global symbol table\n\nextern_ int O_dumpAST;\n"
  },
  {
    "path": "27_Testing_Errors/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n  case T_VOID:\n    type = P_VOID;\n    break;\n  case T_CHAR:\n    type = P_CHAR;\n    break;\n  case T_INT:\n    type = P_INT;\n    break;\n  case T_LONG:\n    type = P_LONG;\n    break;\n  default:\n    fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type.\n// class is the variable's class\nvoid var_declaration(int type, int class) {\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      if (class == C_LOCAL) {\n\tfatal(\"For now, declaration of local arrays is not implemented\");\n      } else {\n\taddglob(Text, pointer_to(type), S_ARRAY, class, 0, Token.intvalue);\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    if (class == C_LOCAL) {\n      if (addlocl(Text, type, S_VARIABLE, class, 1) == -1)\n\tfatals(\"Duplicate local variable declaration\", Text);\n    } else {\n      addglob(Text, type, S_VARIABLE, class, 0, 1);\n    }\n  }\n}\n\n// param_declaration: <null>\n//           | variable_declaration\n//           | variable_declaration ',' param_declaration\n//\n// Parse the parameters in parentheses after the function name.\n// Add them as symbols to the symbol table and return the number\n// of parameters. If id is not -1, there is an existing function\n// prototype, and the function has this symbol slot number.\nstatic int param_declaration(int id) {\n  int type, param_id;\n  int orig_paramcnt;\n  int paramcnt = 0;\n\n  // Add 1 to id so that it's either zero (no prototype), or\n  // it's the position of the zeroth existing parameter in\n  // the symbol table\n  param_id = id + 1;\n\n  // Get any existing prototype parameter count\n  if (param_id)\n    orig_paramcnt = Symtable[id].nelems;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n    // Get the type and identifier\n    // and add it to the symbol table\n    type = parse_type();\n    ident();\n\n    // We have an existing prototype.\n    // Check that this type matches the prototype.\n    if (param_id) {\n      if (type != Symtable[id].type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      param_id++;\n    } else {\n      // Add a new parameter to the new prototype\n      var_declaration(type, C_PARAM);\n    }\n    paramcnt++;\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in parameter list\", Token.token);\n    }\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((id != -1) && (paramcnt != orig_paramcnt))\n    fatals(\"Parameter count mismatch for function\", Symtable[id].name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int id;\n  int nameslot, endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set id to -1\n  if ((id = findsymbol(Text)) != -1)\n    if (Symtable[id].stype != S_FUNCTION)\n      id = -1;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (id == -1) {\n    endlabel = genlabel();\n    nameslot = addglob(Text, type, S_FUNCTION, C_GLOBAL, endlabel, 0);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype symbol slot number\n  lparen();\n  paramcnt = param_declaration(id);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters\n  if (id == -1)\n    Symtable[nameslot].nelems = paramcnt;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n  // This is not just a prototype.\n  // Copy the global parameters to be local parameters\n  if (id == -1)\n    id = nameslot;\n  copyfuncparams(id);\n\n  // Set the Functionid global to the function's symbol-id\n  Functionid = id;\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's id\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, id));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration\n      tree = function_declaration(type);\n\n      // Only a function prototype, no code\n      if (tree == NULL)\n\tcontinue;\n\n      // A real function, generate the assembly code for it\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, C_GLOBAL);\n      semi();\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "27_Testing_Errors/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(int id);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id, int op);\nint cgloadlocal(int id, int op);\nint cgloadglobstr(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(int id, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, int id);\nint cgstorlocal(int r, int id);\nvoid cgglobsym(int id);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint findlocl(char *s);\nint findsymbol(char *s);\nint addglob(char *name, int type, int stype, int class, int endlabel, int size);\nint addlocl(char *name, int type, int stype, int class, int size);\nvoid copyfuncparams(int slot);\nvoid freeloclsyms(void);\n\n// decl.c\nvoid var_declaration(int type, int class);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint parse_type(void);\nint pointer_to(int type);\nint value_at(int type);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "27_Testing_Errors/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND, \n  T_OR, T_XOR, T_AMPER, \n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN= 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n#define NOLABEL\t 0\t\t// Use NOLABEL when we have no label to\n\t\t\t\t// pass to genAST()\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n        C_GLOBAL = 1,\t\t// Globally visible symbol\n        C_LOCAL,\t\t// Locally visible symbol\n        C_PARAM\t\t\t// Locally visible function parameter\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n  int size;\t\t\t// Number of elements in the symbol\n  int posn;\t\t\t// For locals, either the negative offset\n\t\t\t\t// from stack base pointer, or register id\n#define nelems posn\t\t// For functions, # of params\n\t\t\t\t// For structs, # of fields\n};\n"
  },
  {
    "path": "27_Testing_Errors/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Symtable[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  int id;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, Symtable[id].type, id);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, Symtable[id].type, left, NULL, right, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  int id;\n\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // A variable. Check that the variable exists.\n  id = findsymbol(Text);\n  if (id == -1 || Symtable[id].stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, Symtable[id].type, id);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, Symtable[id].type, id);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, Symtable[id].type, id);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, P_CHARPTR, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(binastop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "27_Testing_Errors/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->v.size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->v.size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->v.id, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n  case A_IF:\n    return (genIF(n));\n  case A_WHILE:\n    return (genWHILE(n));\n  case A_FUNCCALL:\n    return (gen_funccall(n));\n  case A_GLUE:\n    // Do each child statement, and free the\n    // registers after each child\n    genAST(n->left, NOLABEL, n->op);\n    genfreeregs();\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    return (NOREG);\n  case A_FUNCTION:\n    // Generate the function's preamble before the code\n    // in the child sub-tree\n    cgfuncpreamble(n->v.id);\n    genAST(n->left, NOLABEL, n->op);\n    cgfuncpostamble(n->v.id);\n    return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n  case A_ADD:\n    return (cgadd(leftreg, rightreg));\n  case A_SUBTRACT:\n    return (cgsub(leftreg, rightreg));\n  case A_MULTIPLY:\n    return (cgmul(leftreg, rightreg));\n  case A_DIVIDE:\n    return (cgdiv(leftreg, rightreg));\n  case A_AND:\n    return (cgand(leftreg, rightreg));\n  case A_OR:\n    return (cgor(leftreg, rightreg));\n  case A_XOR:\n    return (cgxor(leftreg, rightreg));\n  case A_LSHIFT:\n    return (cgshl(leftreg, rightreg));\n  case A_RSHIFT:\n    return (cgshr(leftreg, rightreg));\n  case A_EQ:\n  case A_NE:\n  case A_LT:\n  case A_GT:\n  case A_LE:\n  case A_GE:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, compare registers\n    // and set one to 1 or 0 based on the comparison.\n    if (parentASTop == A_IF || parentASTop == A_WHILE)\n      return (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n    else\n      return (cgcompare_and_set(n->op, leftreg, rightreg));\n  case A_INTLIT:\n    return (cgloadint(n->v.intvalue, n->type));\n  case A_STRLIT:\n    return (cgloadglobstr(n->v.id));\n  case A_IDENT:\n    // Load our value if we are an rvalue\n    // or we are being dereferenced\n    if (n->rvalue || parentASTop == A_DEREF) {\n      if (Symtable[n->v.id].class == C_GLOBAL) {\n\treturn (cgloadglob(n->v.id, n->op));\n      } else {\n\treturn (cgloadlocal(n->v.id, n->op));\n      }\n    } else\n      return (NOREG);\n  case A_ASSIGN:\n    // Are we assigning to an identifier or through a pointer?\n    switch (n->right->op) {\n    case A_IDENT:\n      if (Symtable[n->right->v.id].class == C_GLOBAL)\n\treturn (cgstorglob(leftreg, n->right->v.id));\n      else\n\treturn (cgstorlocal(leftreg, n->right->v.id));\n    case A_DEREF:\n      return (cgstorderef(leftreg, rightreg, n->right->type));\n    default:\n      fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n    }\n  case A_WIDEN:\n    // Widen the child's type to the parent's type\n    return (cgwiden(leftreg, n->left->type, n->type));\n  case A_RETURN:\n    cgreturn(leftreg, Functionid);\n    return (NOREG);\n  case A_ADDR:\n    return (cgaddress(n->v.id));\n  case A_DEREF:\n    // If we are an rvalue, dereference to get the value we point at,\n    // otherwise leave it for A_ASSIGN to store through the pointer\n    if (n->rvalue)\n      return (cgderef(leftreg, n->left->type));\n    else\n      return (leftreg);\n  case A_SCALE:\n    // Small optimisation: use shift if the\n    // scale value is a known power of two\n    switch (n->v.size) {\n    case 2:\n      return (cgshlconst(leftreg, 1));\n    case 4:\n      return (cgshlconst(leftreg, 2));\n    case 8:\n      return (cgshlconst(leftreg, 3));\n    default:\n      // Load a register with the size and\n      // multiply the leftreg by this size\n      rightreg = cgloadint(n->v.size, P_INT);\n      return (cgmul(leftreg, rightreg));\n    }\n  case A_POSTINC:\n  case A_POSTDEC:\n    // Load and decrement the variable's value into a register\n    // and post increment/decrement it\n    if (Symtable[n->v.id].class == C_GLOBAL)\n      return (cgloadglob(n->v.id, n->op));\n    else \n      return (cgloadlocal(n->v.id, n->op));\n  case A_PREINC:\n  case A_PREDEC:\n    // Load and decrement the variable's value into a register\n    // and pre increment/decrement it\n    if (Symtable[n->left->v.id].class == C_GLOBAL)\n      return (cgloadglob(n->left->v.id, n->op));\n    else \n      return (cgloadlocal(n->left->v.id, n->op));\n  case A_NEGATE:\n    return (cgnegate(leftreg));\n  case A_INVERT:\n    return (cginvert(leftreg));\n  case A_LOGNOT:\n    return (cglognot(leftreg));\n  case A_TOBOOL:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, set the register\n    // to 0 or 1 based on it's zeroeness or non-zeroeness\n    return (cgboolean(leftreg, parentASTop, label));\n  default:\n    fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "27_Testing_Errors/lib/printint.c",
    "content": "#include <stdio.h>\nvoid printint(long x) {\n  printf(\"%ld\\n\", x);\n}\n\nvoid printchar(long x) {\n  putc((char)(x & 0x7f), stdout);\n}\n"
  },
  {
    "path": "27_Testing_Errors/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Initialise global variables\nstatic void init() {\n  Line = 1;\n  Putback = '\\n';\n  Globs = 0;\n  Locls = NSYMBOLS - 1;\n  O_dumpAST = 0;\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-T] infile\\n\", prog);\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nint main(int argc, char *argv[]) {\n  int i;\n\n  // Initialise the globals\n  init();\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    if (*argv[i] != '-')\n      break;\n    for (int j = 1; argv[i][j]; j++) {\n      switch (argv[i][j]) {\n      case 'T':\n\tO_dumpAST = 1;\n\tbreak;\n      default:\n\tusage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have an input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Open up the input file\n  if ((Infile = fopen(argv[i], \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", argv[i], strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(\"out.s\", \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create out.s: %s\\n\", strerror(errno));\n    exit(1);\n  }\n  // For now, ensure that printint() and printchar() are defined\n  addglob(\"printint\", P_INT, S_FUNCTION, C_GLOBAL, 0, 0);\n  addglob(\"printchar\", P_VOID, S_FUNCTION, C_GLOBAL, 0, 0);\n\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file and exit\n  return (0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  exit(1);\n}\n"
  },
  {
    "path": "27_Testing_Errors/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n    case 'a':\n      return '\\a';\n    case 'b':\n      return '\\b';\n    case 'f':\n      return '\\f';\n    case 'n':\n      return '\\n';\n    case 'r':\n      return '\\r';\n    case 't':\n      return '\\t';\n    case 'v':\n      return '\\v';\n    case '\\\\':\n      return '\\\\';\n    case '\"':\n      return '\"';\n    case '\\'':\n      return '\\'';\n    default:\n      fatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n  case 'c':\n    if (!strcmp(s, \"char\"))\n      return (T_CHAR);\n    break;\n  case 'e':\n    if (!strcmp(s, \"else\"))\n      return (T_ELSE);\n    break;\n  case 'f':\n    if (!strcmp(s, \"for\"))\n      return (T_FOR);\n    break;\n  case 'i':\n    if (!strcmp(s, \"if\"))\n      return (T_IF);\n    if (!strcmp(s, \"int\"))\n      return (T_INT);\n    break;\n  case 'l':\n    if (!strcmp(s, \"long\"))\n      return (T_LONG);\n    break;\n  case 'r':\n    if (!strcmp(s, \"return\"))\n      return (T_RETURN);\n    break;\n  case 'w':\n    if (!strcmp(s, \"while\"))\n      return (T_WHILE);\n    break;\n  case 'v':\n    if (!strcmp(s, \"void\"))\n      return (T_VOID);\n    break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n  case EOF:\n    t->token = T_EOF;\n    return (0);\n  case '+':\n    if ((c = next()) == '+') {\n      t->token = T_INC;\n    } else {\n      putback(c);\n      t->token = T_PLUS;\n    }\n    break;\n  case '-':\n    if ((c = next()) == '-') {\n      t->token = T_DEC;\n    } else {\n      putback(c);\n      t->token = T_MINUS;\n    }\n    break;\n  case '*':\n    t->token = T_STAR;\n    break;\n  case '/':\n    t->token = T_SLASH;\n    break;\n  case ';':\n    t->token = T_SEMI;\n    break;\n  case '{':\n    t->token = T_LBRACE;\n    break;\n  case '}':\n    t->token = T_RBRACE;\n    break;\n  case '(':\n    t->token = T_LPAREN;\n    break;\n  case ')':\n    t->token = T_RPAREN;\n    break;\n  case '[':\n    t->token = T_LBRACKET;\n    break;\n  case ']':\n    t->token = T_RBRACKET;\n    break;\n  case '~':\n    t->token = T_INVERT;\n    break;\n  case '^':\n    t->token = T_XOR;\n    break;\n  case ',':\n    t->token = T_COMMA;\n    break;\n  case '=':\n    if ((c = next()) == '=') {\n      t->token = T_EQ;\n    } else {\n      putback(c);\n      t->token = T_ASSIGN;\n    }\n    break;\n  case '!':\n    if ((c = next()) == '=') {\n      t->token = T_NE;\n    } else {\n      putback(c);\n      t->token = T_LOGNOT;\n    }\n    break;\n  case '<':\n    if ((c = next()) == '=') {\n      t->token = T_LE;\n    } else if (c == '<') {\n      t->token = T_LSHIFT;\n    } else {\n      putback(c);\n      t->token = T_LT;\n    }\n    break;\n  case '>':\n    if ((c = next()) == '=') {\n      t->token = T_GE;\n    } else if (c == '>') {\n      t->token = T_RSHIFT;\n    } else {\n      putback(c);\n      t->token = T_GT;\n    }\n    break;\n  case '&':\n    if ((c = next()) == '&') {\n      t->token = T_LOGAND;\n    } else {\n      putback(c);\n      t->token = T_AMPER;\n    }\n    break;\n  case '|':\n    if ((c = next()) == '|') {\n      t->token = T_LOGOR;\n    } else {\n      putback(c);\n      t->token = T_OR;\n    }\n    break;\n  case '\\'':\n    // If it's a quote, scan in the\n    // literal character value and\n    // the trailing quote\n    t->intvalue = scanch();\n    t->token = T_INTLIT;\n    if (next() != '\\'')\n      fatal(\"Expected '\\\\'' at end of char literal\");\n    break;\n  case '\"':\n    // Scan in a literal string\n    scanstr(Text);\n    t->token = T_STRLIT;\n    break;\n  default:\n    // If it's a digit, scan the\n    // literal integer value in\n    if (isdigit(c)) {\n      t->intvalue = scanint(c);\n      t->token = T_INTLIT;\n      break;\n    } else if (isalpha(c) || '_' == c) {\n      // Read in a keyword or identifier\n      scanident(c, Text, TEXTLEN);\n\n      // If it's a recognised keyword, return that token\n      if ((tokentype = keyword(Text)) != 0) {\n\tt->token = tokentype;\n\tbreak;\n      }\n      // Not a recognised keyword, so it must be an identifier\n      t->token = T_IDENT;\n      break;\n    }\n    // The character isn't part of any recognised token, error\n    fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "27_Testing_Errors/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Symtable[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Symtable[Functionid].type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n\n    // The beginning of a variable declaration.\n    // Parse the type and get the identifier.\n    // Then parse the rest of the declaration\n    // and skip over the semicolon\n    type = parse_type();\n    ident();\n    var_declaration(type, C_LOCAL);\n    semi();\n    return (NULL);\t\t// No AST generated here\n  case T_IF:\n    return (if_statement());\n  case T_WHILE:\n    return (while_statement());\n  case T_FOR:\n    return (for_statement());\n  case T_RETURN:\n    return (return_statement());\n  default:\n    // For now, see if this is an expression.\n    // This catches assignment statements.\n    return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "27_Testing_Errors/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\n// Skip C_PARAM entries\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (Symtable[i].class == C_PARAM)\n      continue;\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= Locls)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return its slot position or -1 if not found.\nint findlocl(char *s) {\n  int i;\n\n  for (i = Locls + 1; i < NSYMBOLS; i++) {\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new local symbol slot, or die\n// if we've run out of positions.\nstatic int newlocl(void) {\n  int p;\n\n  if ((p = Locls--) <= Globs)\n    fatal(\"Too many local symbols\");\n  return (p);\n}\n\n// Clear all the entries in the\n// local symbol table\nvoid freeloclsyms(void) {\n  Locls = NSYMBOLS - 1;\n}\n\n// Update a symbol at the given slot number in the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + endlabel: if this is a function\n// + posn: Position information for local symbols\nstatic void updatesym(int slot, char *name, int type, int stype,\n\t\t      int class, int endlabel, int size, int posn) {\n  if (slot < 0 || slot >= NSYMBOLS)\n    fatal(\"Invalid symbol slot number in updatesym()\");\n  Symtable[slot].name = strdup(name);\n  Symtable[slot].type = type;\n  Symtable[slot].stype = stype;\n  Symtable[slot].class = class;\n  Symtable[slot].endlabel = endlabel;\n  Symtable[slot].size = size;\n  Symtable[slot].posn = posn;\n}\n\n// Add a global symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + class of the symbol\n// + size: number of elements\n// + endlabel: if this is a function\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int class, int endlabel,\n\t    int size) {\n  int slot;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((slot = findglob(name)) != -1)\n    return (slot);\n\n  // Otherwise get a new slot and fill it in\n  slot = newglob();\n  updatesym(slot, name, type, stype, class, endlabel, size, 0);\n  // Generate the assembly for the symbol if it's global\n  if (class == C_GLOBAL)\n    genglobsym(slot);\n  // Return the slot number\n  return (slot);\n}\n\n// Add a local symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// Return the slot number in the symbol table, -1 if a duplicate entry\nint addlocl(char *name, int type, int stype, int class, int size) {\n  int localslot;\n\n  // If this is already in the symbol table, return an error\n  if ((localslot = findlocl(name)) != -1)\n    return (-1);\n\n  // Otherwise get a new symbol slot and a position for this local.\n  // Update the local symbol table entry.\n  localslot = newlocl();\n  updatesym(localslot, name, type, stype, class, 0, size, 0);\n\n  // Return the local symbol's slot\n  return (localslot);\n}\n\n// Given a function's slot number, copy the global parameters\n// from its prototype to be local parameters\nvoid copyfuncparams(int slot) {\n  int i, id = slot + 1;\n\n  for (i = 0; i < Symtable[slot].nelems; i++, id++) {\n    addlocl(Symtable[id].name, Symtable[id].type, Symtable[id].stype,\n\t    Symtable[id].class, Symtable[id].size);\n  }\n}\n\n\n// Determine if the symbol s is in the symbol table.\n// Return its slot position or -1 if not found.\nint findsymbol(char *s) {\n  int slot;\n\n  slot = findlocl(s);\n  if (slot == -1)\n    slot = findglob(s);\n  return (slot);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:15 on line 3\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input32.c",
    "content": "Unknown variable:cow on line 2\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input33.c",
    "content": "Incompatible type to return on line 2\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input34.c",
    "content": "For now, declaration of local arrays is not implemented on line 2\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 2\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:3 on line 2\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input37.c",
    "content": "Unexpected token in parameter list:15 on line 1\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:3 on line 2\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 2\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input40.c",
    "content": "No return for function with non-void type on line 2\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input41.c",
    "content": "Can't return from a void function on line 1\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input42.c",
    "content": "Undeclared function:fred on line 1\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input43.c",
    "content": "Undeclared array:b on line 1\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input44.c",
    "content": "Unknown variable:z on line 1\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 1\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 1\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 1\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 1\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 4\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 4\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 2\n"
  },
  {
    "path": "27_Testing_Errors/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 3\n"
  },
  {
    "path": "27_Testing_Errors/tests/input01.c",
    "content": "void main()\n{ printint(12 * 3);\n  printint(18 - 2 * 4);\n  printint(1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input02.c",
    "content": "void main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printint(fred + jim);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input03.c",
    "content": "void main()\n{\n  int x;\n  x= 1;     printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n  x= x + 1; printint(x);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input04.c",
    "content": "void main()\n{\n  int x;\n  x= 7 < 9;  printint(x);\n  x= 7 <= 9; printint(x);\n  x= 7 != 9; printint(x);\n  x= 7 == 7; printint(x);\n  x= 7 >= 7; printint(x);\n  x= 7 <= 7; printint(x);\n  x= 9 > 7;  printint(x);\n  x= 9 >= 7; printint(x);\n  x= 9 != 7; printint(x);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input05.c",
    "content": "void main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printint(i);\n  } else {\n    printint(j);\n  }\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input06.c",
    "content": "void main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printint(i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input07.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input08.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input09.c",
    "content": "void main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printint(i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printint(2 * b - a); }\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input10.c",
    "content": "void main()\n{\n  int i; char j;\n\n  j= 20; printint(j);\n  i= 10; printint(i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 2; j= j + 1) { printint(j); }\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input11.c",
    "content": "int main()\n{\n  int i; char j; long k;\n\n  i= 10; printint(i);\n  j= 20; printint(j);\n  k= 30; printint(k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printint(i); }\n  for (j= 253; j != 4; j= j + 1) { printint(j); }\n  for (k= 1;   k <= 5; k= k + 1) { printint(k); }\n  return(i);\n  printint(12345);\n  return(3);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input12.c",
    "content": "int fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printint(x);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input13.c",
    "content": "int fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printint(23);\n  result= fred(10);\n  dummy= printint(result);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input14.c",
    "content": "int fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printint(10);\n  result= fred(15);\n  printint(result);\n  printint(fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input15.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printint(a);\n  b= &a; c= *b; printint(c);\n\n  d= 12; printint(d);\n  e= &d; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input16.c",
    "content": "int   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printint(c);\n  e= &c + 1; f= *e; printint(f);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input17.c",
    "content": "int main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printint(a);\n  e= &d; *e= 12; printint(d);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input18.c",
    "content": "int main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printint(a);\n  printint(b);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input18a.c",
    "content": "int   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printint(a);\n  d= &c; *d= 16; printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input19.c",
    "content": "int a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printint(e);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input20.c",
    "content": "int a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printint(a);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input21.c",
    "content": "char  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printint(c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printchar(*str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input22.c",
    "content": "char a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printint(a);\n  e= 5; f= 7; d= e + f++; printint(d);\n  h= 5; i= 7; g= h + i++; printint(g);\n  a= b-- + c; printint(a);\n  d= e-- + f; printint(d);\n  g= h-- + i; printint(g);\n  a= ++b + c; printint(a);\n  d= ++e + f; printint(d);\n  g= ++h + i; printint(g);\n  a= b * --c; printint(a);\n  d= e * --f; printint(d);\n  g= h * --i; printint(g);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input23.c",
    "content": "char *str;\nint   x;\n\nint main() {\n  x= -23; printint(x);\n  printint(-10 * -10);\n\n  x= 1; x= ~x; printint(x);\n\n  x= 2 > 5; printint(x);\n  x= !x; printint(x);\n  x= !x; printint(x);\n\n  x= 13; if (x) { printint(13); }\n  x= 0; if (!x) { printint(14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printchar(*str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input24.c",
    "content": "int a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printint(a & b);\n  printint(a | b);\n  printint(a ^ b);\n  printint(1 << 3);\n  printint(63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input25.c",
    "content": "int a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printint(x); printint(y); printint(z);\n  a= 5; b= 15; c= 25;\n  printint(a); printint(b); printint(c);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input26.c",
    "content": "int main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printint(a);\n  b= 23; printint(b);\n  c= 34; printint(c);\n  d= 44; printint(d);\n  e= 54; printint(e);\n  f= 64; printint(f);\n  g= 74; printint(g);\n  h= 84; printint(h);\n  i= 94; printint(i);\n  j= 95; printint(j);\n  k= 96; printint(k);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input27.c",
    "content": "int param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printint(a); printint(b); printint(c); printint(d);\n  printint(e); printint(f); printint(g); printint(h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printint(a); printint(b); printint(c); printint(d); printint(e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input28.c",
    "content": "int param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printint(a); printint(b); printint(c); printint(d);\n  printint(e); printint(f); printint(g); printint(h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printint(x);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input29.c",
    "content": "int param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printint(a); printint(b); printint(c); printint(d);\n  printint(e); printint(f); printint(g); printint(h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printint(x);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input30.c",
    "content": "int open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input31.c",
    "content": "int main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input32.c",
    "content": "int main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input33.c",
    "content": "int main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input34.c",
    "content": "int main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input35.c",
    "content": "int fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input36.c",
    "content": "int fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "27_Testing_Errors/tests/input37.c",
    "content": "int fred(int a, char b +, int z);\n"
  },
  {
    "path": "27_Testing_Errors/tests/input38.c",
    "content": "int fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "27_Testing_Errors/tests/input39.c",
    "content": "int main() { int a; }\n"
  },
  {
    "path": "27_Testing_Errors/tests/input40.c",
    "content": "int main() { int a; a= 5; }\n"
  },
  {
    "path": "27_Testing_Errors/tests/input41.c",
    "content": "void fred() { return(5); }\n"
  },
  {
    "path": "27_Testing_Errors/tests/input42.c",
    "content": "int main() { fred(5); }\n"
  },
  {
    "path": "27_Testing_Errors/tests/input43.c",
    "content": "int main() { int a; a= b[4]; }\n"
  },
  {
    "path": "27_Testing_Errors/tests/input44.c",
    "content": "int main() { int a; a= z; }\n"
  },
  {
    "path": "27_Testing_Errors/tests/input45.c",
    "content": "int main() { int a; a= &5; }\n"
  },
  {
    "path": "27_Testing_Errors/tests/input46.c",
    "content": "int main() { int a; a= *5; }\n"
  },
  {
    "path": "27_Testing_Errors/tests/input47.c",
    "content": "int main() { int a; a= ++5; }\n"
  },
  {
    "path": "27_Testing_Errors/tests/input48.c",
    "content": "int main() { int a; a= --5; }\n"
  },
  {
    "path": "27_Testing_Errors/tests/input49.c",
    "content": "int main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input50.c",
    "content": "int main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input51.c",
    "content": "int main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input52.c",
    "content": "int main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../comp1 ]\nthen (cd ..; make)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../comp1 $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i ../lib/printint.c\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input30.c",
    "content": "int open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "27_Testing_Errors/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "27_Testing_Errors/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../comp1 ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../comp1 $i\n\n\t  # Assemble the output, run it\n\t  # and get the output in trial.$i\n          cc -o out out.s ../lib/printint.c\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../comp1 $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "27_Testing_Errors/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn $i\n\n\t  # Assemble the output, run it\n\t  # and get the output in trial.$i\n          nasm -f elf64 out.s\n          cc -no-pie -fno-plt -Wall -o out out.o ../lib/printint.c\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "27_Testing_Errors/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n  case A_IF:\n    Lfalse = gendumplabel();\n    for (int i = 0; i < level; i++)\n      fprintf(stdout, \" \");\n    fprintf(stdout, \"A_IF\");\n    if (n->right) {\n      Lend = gendumplabel();\n      fprintf(stdout, \", end L%d\", Lend);\n    }\n    fprintf(stdout, \"\\n\");\n    dumpAST(n->left, Lfalse, level + 2);\n    dumpAST(n->mid, NOLABEL, level + 2);\n    if (n->right)\n      dumpAST(n->right, NOLABEL, level + 2);\n    return;\n  case A_WHILE:\n    Lstart = gendumplabel();\n    for (int i = 0; i < level; i++)\n      fprintf(stdout, \" \");\n    fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n    Lend = gendumplabel();\n    dumpAST(n->left, Lend, level + 2);\n    dumpAST(n->right, NOLABEL, level + 2);\n    return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n  case A_GLUE:\n    fprintf(stdout, \"\\n\\n\");\n    return;\n  case A_FUNCTION:\n    fprintf(stdout, \"A_FUNCTION %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_ADD:\n    fprintf(stdout, \"A_ADD\\n\");\n    return;\n  case A_SUBTRACT:\n    fprintf(stdout, \"A_SUBTRACT\\n\");\n    return;\n  case A_MULTIPLY:\n    fprintf(stdout, \"A_MULTIPLY\\n\");\n    return;\n  case A_DIVIDE:\n    fprintf(stdout, \"A_DIVIDE\\n\");\n    return;\n  case A_EQ:\n    fprintf(stdout, \"A_EQ\\n\");\n    return;\n  case A_NE:\n    fprintf(stdout, \"A_NE\\n\");\n    return;\n  case A_LT:\n    fprintf(stdout, \"A_LE\\n\");\n    return;\n  case A_GT:\n    fprintf(stdout, \"A_GT\\n\");\n    return;\n  case A_LE:\n    fprintf(stdout, \"A_LE\\n\");\n    return;\n  case A_GE:\n    fprintf(stdout, \"A_GE\\n\");\n    return;\n  case A_INTLIT:\n    fprintf(stdout, \"A_INTLIT %d\\n\", n->v.intvalue);\n    return;\n  case A_STRLIT:\n    fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->v.id);\n    return;\n  case A_IDENT:\n    if (n->rvalue)\n      fprintf(stdout, \"A_IDENT rval %s\\n\", Symtable[n->v.id].name);\n    else\n      fprintf(stdout, \"A_IDENT %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_ASSIGN:\n    fprintf(stdout, \"A_ASSIGN\\n\");\n    return;\n  case A_WIDEN:\n    fprintf(stdout, \"A_WIDEN\\n\");\n    return;\n  case A_RETURN:\n    fprintf(stdout, \"A_RETURN\\n\");\n    return;\n  case A_FUNCCALL:\n    fprintf(stdout, \"A_FUNCCALL %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_ADDR:\n    fprintf(stdout, \"A_ADDR %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_DEREF:\n    if (n->rvalue)\n      fprintf(stdout, \"A_DEREF rval\\n\");\n    else\n      fprintf(stdout, \"A_DEREF\\n\");\n    return;\n  case A_SCALE:\n    fprintf(stdout, \"A_SCALE %d\\n\", n->v.size);\n    return;\n  case A_PREINC:\n    fprintf(stdout, \"A_PREINC %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_PREDEC:\n    fprintf(stdout, \"A_PREDEC %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_POSTINC:\n    fprintf(stdout, \"A_POSTINC\\n\");\n    return;\n  case A_POSTDEC:\n    fprintf(stdout, \"A_POSTDEC\\n\");\n    return;\n  case A_NEGATE:\n    fprintf(stdout, \"A_NEGATE\\n\");\n    return;\n  default:\n    fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "27_Testing_Errors/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  if (type == P_CHAR || type == P_INT || type == P_LONG)\n    return (1);\n  return (0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  if (type == P_VOIDPTR || type == P_CHARPTR ||\n      type == P_INTPTR || type == P_LONGPTR)\n    return (1);\n  return (0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n  case P_VOID:\n    newtype = P_VOIDPTR;\n    break;\n  case P_CHAR:\n    newtype = P_CHARPTR;\n    break;\n  case P_INT:\n    newtype = P_INTPTR;\n    break;\n  case P_LONG:\n    newtype = P_LONGPTR;\n    break;\n  default:\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n  case P_VOIDPTR:\n    newtype = P_VOID;\n    break;\n  case P_CHARPTR:\n    newtype = P_CHAR;\n    break;\n  case P_INTPTR:\n    newtype = P_INT;\n    break;\n  case P_LONGPTR:\n    newtype = P_LONG;\n    break;\n  default:\n    fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/Makefile",
    "content": "HSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out\n\ntest: cwj tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "28_Runtime_Flags/Readme.md",
    "content": "# Part 28: Adding More Run-time Flags\n\nThis part of our compiler writing journey really doesn't have anything to\ndo with scanning, parsing, semantic analysis or code generation. In this\npart, I add the `-c`, `-S` and `-o` run-time flags to the compiler so\nthat it behaves more like a traditional Unix C compiler.\n\nSo, if that's not interesting, feel free to skip to the next part of the\njourney.\n\n## Compilation Steps\n\nUp to now, our compiler has only been outputting assembly files. But there\nare more steps to convert a source code file in a high-level language to\nan executable file:\n\n + Scan and parse the source code file to generate assembly output\n + Assemble the assembly output to an [object file](https://en.wikipedia.org/wiki/Object_file)\n + [Link](https://en.wikipedia.org/wiki/Linker_(computing)) one or more object files to produce the executable file\n\nWe've been doing the last two steps manually or with our Makefile, but I'm\ngoing to modify the compiler to call an external assembler and linker to\nperform the last two steps.\n\nTo do this, I'm going to rearrange some of the code in `main.c` and also\nwrite more functions in `main.c` to do the assembling and linking. Most \nof this code is typical string and file handling code done in C, so I'll\ngo through the code but it may only be interesting if you've never seen\nthis sort of code.\n\n## Parsing the Command-Line Flags\n\nI've renamed the compiler to be `cwj` to reflect the name of the project.\nWhen you run it with no command-line arguments, it now gives this usage\nmessage:\n\n```\n$ ./cwj \nUsage: ./cwj [-vcST] [-o outfile] file [file ...]\n       -v give verbose output of the compilation stages\n       -c generate object files but don't link them\n       -S generate assembly files but don't link them\n       -T dump the AST trees for each input file\n       -o outfile, produce the outfile executable file\n```\n\nWe now allow multiple source code files as inputs. We have four boolean\nflags, `-v`, `-c`, `-S` and `-T`, and we can now name the output executable\nfile.\n\nThe `argv[]` parsing code in `main()` is now changed to deal with this, and\nthere are several more option variables to hold the results.\n\n```c\n  // Initialise our variables\n  O_dumpAST = 0;        // If true, dump the AST trees\n  O_keepasm = 0;        // If true, keep any assembly files\n  O_assemble = 0;       // If true, assemble the assembly files\n  O_dolink = 1;         // If true, link the object files\n  O_verbose = 0;        // If true, print info on compilation stages\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n      case 'o':\n        outfilename = argv[++i]; break;         // Save & skip to next argument\n      case 'T':\n        O_dumpAST = 1; break;\n      case 'c':\n        O_assemble = 1; O_keepasm = 0; O_dolink = 0; break;\n      case 'S':\n        O_keepasm = 1; O_assemble = 0; O_dolink = 0; break;\n      case 'v':\n        O_verbose = 1; break;\n      default:\n        usage(argv[0]);\n      }\n    }\n  }\n```\n\nNote that some options are mutually exclusive, e.g. if we only want assembly\noutput with `-S`, then we don't want to link or create object files.\n\n## Performing the Compilation Stages\n\nWith the command-line flags parsed, we can now run the compilation stages.\nWe can compile and assemble each input file easily, but there may be a\nnumber of object files that we need to link together at the end. So we have\nsome local variables in `main()` to store the object file names:\n\n```c\n#define MAXOBJ 100\n  char *objlist[MAXOBJ];        // List of object file names\n  int objcnt = 0;               // Position to insert next name\n```\n\nWe first process all the input source files in turn:\n\n```c\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);      // Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);   // Assemble it to object format\n      if (objcnt == (MAXOBJ - 2)) {\n        fprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n        exit(1);\n      }\n      objlist[objcnt++] = objfile;      // Add the object file's name\n      objlist[objcnt] = NULL;           // to the list of object files\n    }\n\n    if (!O_keepasm)                     // Remove the assembly file if\n      unlink(asmfile);                  // we don't need to keep it\n    i++;\n  } \n```\n\n`do_compile()` has the code that used to be in `main()` to\nopen the file, parse it ourselves and generate the assembly file.\nBut we can't open up the hard-coded filename\n`out.s` like we used to; we now need to convert `filename.c` to `filename.s`.\n\n## Altering the Input Filename\n\nWe have a helper function to alter filenames.\n\n```c\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL) return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL) return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0') return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix; *posn = '\\0';\n  return (newstr);\n}\n```\n\nOnly the `strdup()`, `strrchr()` and the last two lines do any real work;\nthe rest is error checking.\n\n## Doing the Compilation\n\nHere is the code that we used to have, now repackaged into a new function.\n\n```c\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Open up the input file\n  if ((Infile = fopen(filename, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n            strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;                     // Reset the scanner\n  Putback = '\\n';\n  clear_symtable();             // Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);                 // Get the first token from the input\n  genpreamble();                // Output the preamble\n  global_declarations();        // Parse the global declarations\n  genpostamble();               // Output the postamble\n  fclose(Outfile);              // Close the output file\n  return (Outfilename);\n}\n```\n\nThere's very little new code here, just the call to `alter_suffix()` to\nget the correct output file's name.\n\nThere is one important change: the assembly output file is now a global\nvariable called `Outfilename`. This allows the `fatal()` function and\nfriends in `misc.c` to remove assembly files if we never fully generated them,\ne.g.\n\n```c\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n```\n\n## Assembling the Above Output\n\nNow that we have assembly output files, we can now call an external\nassembler to do this. This is defined as ASCMD in `defs.h`. Here's\nthe function to do this:\n\n```c\n#define ASCMD \"as -o \"\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose) printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) { fprintf(stderr, \"Assembly of %s failed\\n\", filename); exit(1); }\n  return (outfilename);\n}\n```\n\nI'm using `snprintf()` to build the assembly command which we will run.\nIf the user used the `-v` command-line flag, this command will be shown to\nthem. Then we use `system()` to execute this Linux command. Example:\n\n```\n$ ./cwj -v -c tests/input54.c \ncompiling tests/input54.c\nas -o  tests/input54.o tests/input54.s\n```\n\n## Linking the Object Files\n\nDown in `main()` we build up a list of object files that `do_assemble()`\nreturns to us:\n\n```c\n      objlist[objcnt++] = objfile;      // Add the object file's name\n      objlist[objcnt] = NULL;           // to the list of object files\n```\n\nSo, when we need to link them all together, we need to pass this list to\nthe `do_link()` function. The code is similar to `do_assemble()` in that\nit uses `snprintf()` and `system()`. The difference is that we must\ntrack where we are up to in our command buffer, and how much room is left\nto do more `snprintf()`ing.\n\n```c\n#define LDCMD \"cc -o \"\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt; size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt; size -= cnt; objlist++;\n  }\n\n  if (O_verbose) printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) { fprintf(stderr, \"Linking failed\\n\"); exit(1); }\n}\n```\n\nOne annoyance is that I'm still calling the external C compiler `cc` to do\nthe linking. We really should be able to break this dependency on another\ncompiler.\n\nA long time ago, it was possible to link a set of object files manually\nby doing, e.g.\n\n```\n  $ ln -o out /lib/crt0.o file1.o file.o /usr/lib/libc.a\n```\n\nI assume that it should be possible to do a similar command on current\nLinux, but so far my Google-fu isn't enough to work this out. If you read\nthis and know the answer, let me know!\n\n## Losing `printint()` and `printchar()`\n\nNow that we can call `printf()` directly in the programs that we can compile,\nwe no longer need our hand-written `printint()` and `printchar()` functions.\nI've removed `lib/printint.c`, and I've updated all of the tests in the\n`tests/` directory to use `printf()`.\n\nI've also updated the `tests/mktests` and `tests/runtests` scripts so that\nthey use the new compiler command-line arguments, and ditto the top-level\n`Makefile`. So a `make test` still runs our regression tests OK.\n\n## Conclusion and What's Next\n\nThat's about it for this part of our journey. Our compiler now feels like\nthe traditional Unix compilers that I'm used to.\n\nI did promise to add in support for an external pre-processor in this\nstep, but I decided against it. The main reason is that I would need to\nparse the filenames and line numbers that the pre-processor embeds in its\noutput, e.g.\n\n```c\n# 1 \"tests/input54.c\"\n# 1 \"<built-in>\"\n# 1 \"<command-line>\"\n# 31 \"<command-line>\"\n# 1 \"/usr/include/stdc-predef.h\" 1 3 4\n# 32 \"<command-line>\" 2\n# 1 \"tests/input54.c\"\nint printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n```\n\n\nIn the next part of our compiler writing journey, we will\nlook at adding support for structs to our compiler. I think we\nmight have to do another design step first before we get to\nimplementing the changes. [Next step](../29_Refactoring/Readme.md)\n"
  },
  {
    "path": "28_Runtime_Flags/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  int i;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack\n  // Stop after no more than six parameter registers\n  for (i = NSYMBOLS - 1; i > Locls; i--) {\n    if (Symtable[i].class != C_PARAM)\n      break;\n    if (i < NSYMBOLS - 6)\n      break;\n    Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    cgstorlocal(paramReg--, i);\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (; i > Locls; i--) {\n    if (Symtable[i].class == C_PARAM) {\n      Symtable[i].posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    }\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n    break;\n  case P_INT:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    break;\n  case P_INT:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    break;\n  default:\n    fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", id, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(int id, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", Symtable[id].name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r],\n\t    Symtable[id].name);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r],\n\t    Symtable[id].name);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r],\n\t    Symtable[id].name);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r],\n\t    Symtable[id].posn);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r],\n\t    Symtable[id].posn);\n    break;\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r],\n\t    Symtable[id].posn);\n    break;\n  default:\n    fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n    break;\n  case P_LONG:\n    fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n    break;\n  default:\n    fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n    fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  default:\n    fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  case P_LONG:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 4, 4, 4, 4 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n  case 1:\n    fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n    break;\n  case 4:\n    fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n    break;\n  default:\n    fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n    break;\n  case P_INT:\n  case P_LONG:\n    fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  int i;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack\n  // Stop after no more than six parameter registers\n  for (i = NSYMBOLS - 1; i > Locls; i--) {\n    if (Symtable[i].class != C_PARAM)\n      break;\n    if (i < NSYMBOLS - 6)\n      break;\n    Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    cgstorlocal(paramReg--, i);\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (; i > Locls; i--) {\n    if (Symtable[i].class == C_PARAM) {\n      Symtable[i].posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    }\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Symtable[id].name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              Symtable[id].name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Symtable[id].name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              Symtable[id].posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n              Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n              Symtable[id].posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], id);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(int id, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Symtable[id].name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              dreglist[r]);\n      break;\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Array of type sizes in P_XXX order.\n// 0 means no size.\nstatic int psize[] = { 0, 0, 1, 4, 8, 8, 8, 8, 8 };\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  // Check the type is valid\n  if (type < P_NONE || type > P_LONGPTR)\n    fatal(\"Bad type in cgprimsize()\");\n  return (psize[type]);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  // original version\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch(typesize) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(typesize) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", Symtable[id].size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", Symtable[id].size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", Symtable[id].size);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Symtable[id].name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            Symtable[id].posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ int Locls;\t\t// Position of next free local symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Outfilename;\t// Name of file we opened as Outfile\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Symtable[NSYMBOLS];\t// Global symbol table\n\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "28_Runtime_Flags/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n  case T_VOID:\n    type = P_VOID;\n    break;\n  case T_CHAR:\n    type = P_CHAR;\n    break;\n  case T_INT:\n    type = P_INT;\n    break;\n  case T_LONG:\n    type = P_LONG;\n    break;\n  default:\n    fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type.\n// class is the variable's class\nvoid var_declaration(int type, int class) {\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      if (class == C_LOCAL) {\n\tfatal(\"For now, declaration of local arrays is not implemented\");\n      } else {\n\taddglob(Text, pointer_to(type), S_ARRAY, class, 0, Token.intvalue);\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    if (class == C_LOCAL) {\n      if (addlocl(Text, type, S_VARIABLE, class, 1) == -1)\n\tfatals(\"Duplicate local variable declaration\", Text);\n    } else {\n      addglob(Text, type, S_VARIABLE, class, 0, 1);\n    }\n  }\n}\n\n// param_declaration: <null>\n//           | variable_declaration\n//           | variable_declaration ',' param_declaration\n//\n// Parse the parameters in parentheses after the function name.\n// Add them as symbols to the symbol table and return the number\n// of parameters. If id is not -1, there is an existing function\n// prototype, and the function has this symbol slot number.\nstatic int param_declaration(int id) {\n  int type, param_id;\n  int orig_paramcnt;\n  int paramcnt = 0;\n\n  // Add 1 to id so that it's either zero (no prototype), or\n  // it's the position of the zeroth existing parameter in\n  // the symbol table\n  param_id = id + 1;\n\n  // Get any existing prototype parameter count\n  if (param_id)\n    orig_paramcnt = Symtable[id].nelems;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n    // Get the type and identifier\n    // and add it to the symbol table\n    type = parse_type();\n    ident();\n\n    // We have an existing prototype.\n    // Check that this type matches the prototype.\n    if (param_id) {\n      if (type != Symtable[id].type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      param_id++;\n    } else {\n      // Add a new parameter to the new prototype\n      var_declaration(type, C_PARAM);\n    }\n    paramcnt++;\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in parameter list\", Token.token);\n    }\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((id != -1) && (paramcnt != orig_paramcnt))\n    fatals(\"Parameter count mismatch for function\", Symtable[id].name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int id;\n  int nameslot, endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set id to -1\n  if ((id = findsymbol(Text)) != -1)\n    if (Symtable[id].stype != S_FUNCTION)\n      id = -1;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (id == -1) {\n    endlabel = genlabel();\n    nameslot = addglob(Text, type, S_FUNCTION, C_GLOBAL, endlabel, 0);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype symbol slot number\n  lparen();\n  paramcnt = param_declaration(id);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters\n  if (id == -1)\n    Symtable[nameslot].nelems = paramcnt;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n  // This is not just a prototype.\n  // Copy the global parameters to be local parameters\n  if (id == -1)\n    id = nameslot;\n  copyfuncparams(id);\n\n  // Set the Functionid global to the function's symbol-id\n  Functionid = id;\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's id\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, id));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration\n      tree = function_declaration(type);\n\n      // Only a function prototype, no code\n      if (tree == NULL)\n\tcontinue;\n\n      // A real function, generate the assembly code for it\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, C_GLOBAL);\n      semi();\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "28_Runtime_Flags/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(int id);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id, int op);\nint cgloadlocal(int id, int op);\nint cgloadglobstr(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(int id, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, int id);\nint cgstorlocal(int r, int id);\nvoid cgglobsym(int id);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint findlocl(char *s);\nint findsymbol(char *s);\nint addglob(char *name, int type, int stype, int class, int endlabel, int size);\nint addlocl(char *name, int type, int stype, int class, int size);\nvoid copyfuncparams(int slot);\nvoid freeloclsyms(void);\nvoid clear_symtable(void);\n\n// decl.c\nvoid var_declaration(int type, int class);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint parse_type(void);\nint pointer_to(int type);\nint value_at(int type);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "28_Runtime_Flags/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n#define TEXTLEN\t\t512\t// Length of symbols in input\n#define NSYMBOLS        1024\t// Number of symbol table entries\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND, \n  T_OR, T_XOR, T_AMPER, \n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN= 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  } v;\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\n#define NOREG\t-1\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n#define NOLABEL\t 0\t\t// Use NOLABEL when we have no label to\n\t\t\t\t// pass to genAST()\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n        C_GLOBAL = 1,\t\t// Globally visible symbol\n        C_LOCAL,\t\t// Locally visible symbol\n        C_PARAM\t\t\t// Locally visible function parameter\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int endlabel;\t\t\t// For S_FUNCTIONs, the end label\n  int size;\t\t\t// Number of elements in the symbol\n  int posn;\t\t\t// For locals, either the negative offset\n\t\t\t\t// from stack base pointer, or register id\n#define nelems posn\t\t// For functions, # of params\n\t\t\t\t// For structs, # of fields\n};\n"
  },
  {
    "path": "28_Runtime_Flags/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Symtable[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  int id;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, Symtable[id].type, id);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, Symtable[id].type, left, NULL, right, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  int id;\n\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // A variable. Check that the variable exists.\n  id = findsymbol(Text);\n  if (id == -1 || Symtable[id].stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, Symtable[id].type, id);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, Symtable[id].type, id);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, Symtable[id].type, id);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, P_CHARPTR, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(binastop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->v.size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->v.size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->v.id, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n  case A_IF:\n    return (genIF(n));\n  case A_WHILE:\n    return (genWHILE(n));\n  case A_FUNCCALL:\n    return (gen_funccall(n));\n  case A_GLUE:\n    // Do each child statement, and free the\n    // registers after each child\n    genAST(n->left, NOLABEL, n->op);\n    genfreeregs();\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    return (NOREG);\n  case A_FUNCTION:\n    // Generate the function's preamble before the code\n    // in the child sub-tree\n    cgfuncpreamble(n->v.id);\n    genAST(n->left, NOLABEL, n->op);\n    cgfuncpostamble(n->v.id);\n    return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n  case A_ADD:\n    return (cgadd(leftreg, rightreg));\n  case A_SUBTRACT:\n    return (cgsub(leftreg, rightreg));\n  case A_MULTIPLY:\n    return (cgmul(leftreg, rightreg));\n  case A_DIVIDE:\n    return (cgdiv(leftreg, rightreg));\n  case A_AND:\n    return (cgand(leftreg, rightreg));\n  case A_OR:\n    return (cgor(leftreg, rightreg));\n  case A_XOR:\n    return (cgxor(leftreg, rightreg));\n  case A_LSHIFT:\n    return (cgshl(leftreg, rightreg));\n  case A_RSHIFT:\n    return (cgshr(leftreg, rightreg));\n  case A_EQ:\n  case A_NE:\n  case A_LT:\n  case A_GT:\n  case A_LE:\n  case A_GE:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, compare registers\n    // and set one to 1 or 0 based on the comparison.\n    if (parentASTop == A_IF || parentASTop == A_WHILE)\n      return (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n    else\n      return (cgcompare_and_set(n->op, leftreg, rightreg));\n  case A_INTLIT:\n    return (cgloadint(n->v.intvalue, n->type));\n  case A_STRLIT:\n    return (cgloadglobstr(n->v.id));\n  case A_IDENT:\n    // Load our value if we are an rvalue\n    // or we are being dereferenced\n    if (n->rvalue || parentASTop == A_DEREF) {\n      if (Symtable[n->v.id].class == C_GLOBAL) {\n\treturn (cgloadglob(n->v.id, n->op));\n      } else {\n\treturn (cgloadlocal(n->v.id, n->op));\n      }\n    } else\n      return (NOREG);\n  case A_ASSIGN:\n    // Are we assigning to an identifier or through a pointer?\n    switch (n->right->op) {\n    case A_IDENT:\n      if (Symtable[n->right->v.id].class == C_GLOBAL)\n\treturn (cgstorglob(leftreg, n->right->v.id));\n      else\n\treturn (cgstorlocal(leftreg, n->right->v.id));\n    case A_DEREF:\n      return (cgstorderef(leftreg, rightreg, n->right->type));\n    default:\n      fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n    }\n  case A_WIDEN:\n    // Widen the child's type to the parent's type\n    return (cgwiden(leftreg, n->left->type, n->type));\n  case A_RETURN:\n    cgreturn(leftreg, Functionid);\n    return (NOREG);\n  case A_ADDR:\n    return (cgaddress(n->v.id));\n  case A_DEREF:\n    // If we are an rvalue, dereference to get the value we point at,\n    // otherwise leave it for A_ASSIGN to store through the pointer\n    if (n->rvalue)\n      return (cgderef(leftreg, n->left->type));\n    else\n      return (leftreg);\n  case A_SCALE:\n    // Small optimisation: use shift if the\n    // scale value is a known power of two\n    switch (n->v.size) {\n    case 2:\n      return (cgshlconst(leftreg, 1));\n    case 4:\n      return (cgshlconst(leftreg, 2));\n    case 8:\n      return (cgshlconst(leftreg, 3));\n    default:\n      // Load a register with the size and\n      // multiply the leftreg by this size\n      rightreg = cgloadint(n->v.size, P_INT);\n      return (cgmul(leftreg, rightreg));\n    }\n  case A_POSTINC:\n  case A_POSTDEC:\n    // Load and decrement the variable's value into a register\n    // and post increment/decrement it\n    if (Symtable[n->v.id].class == C_GLOBAL)\n      return (cgloadglob(n->v.id, n->op));\n    else \n      return (cgloadlocal(n->v.id, n->op));\n  case A_PREINC:\n  case A_PREDEC:\n    // Load and decrement the variable's value into a register\n    // and pre increment/decrement it\n    if (Symtable[n->left->v.id].class == C_GLOBAL)\n      return (cgloadglob(n->left->v.id, n->op));\n    else \n      return (cgloadlocal(n->left->v.id, n->op));\n  case A_NEGATE:\n    return (cgnegate(leftreg));\n  case A_INVERT:\n    return (cginvert(leftreg));\n  case A_LOGNOT:\n    return (cglognot(leftreg));\n  case A_TOBOOL:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, set the register\n    // to 0 or 1 based on it's zeroeness or non-zeroeness\n    return (cgboolean(leftreg, parentASTop, label));\n  default:\n    fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "28_Runtime_Flags/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Open up the input file\n  if ((Infile = fopen(filename, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr, \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\n#define MAXOBJ 100\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n      case 'o':\n\toutfilename = argv[++i];\t// Save & skip to next argument\n\tbreak;\n      case 'T':\n\tO_dumpAST = 1;\n\tbreak;\n      case 'c':\n\tO_assemble = 1;\n\tO_keepasm = 0;\n\tO_dolink = 0;\n\tbreak;\n      case 'S':\n\tO_keepasm = 1;\n\tO_assemble = 0;\n\tO_dolink = 0;\n\tbreak;\n      case 'v':\n\tO_verbose = 1;\n\tbreak;\n      default:\n\tusage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n    case 'a':\n      return '\\a';\n    case 'b':\n      return '\\b';\n    case 'f':\n      return '\\f';\n    case 'n':\n      return '\\n';\n    case 'r':\n      return '\\r';\n    case 't':\n      return '\\t';\n    case 'v':\n      return '\\v';\n    case '\\\\':\n      return '\\\\';\n    case '\"':\n      return '\"';\n    case '\\'':\n      return '\\'';\n    default:\n      fatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n  case 'c':\n    if (!strcmp(s, \"char\"))\n      return (T_CHAR);\n    break;\n  case 'e':\n    if (!strcmp(s, \"else\"))\n      return (T_ELSE);\n    break;\n  case 'f':\n    if (!strcmp(s, \"for\"))\n      return (T_FOR);\n    break;\n  case 'i':\n    if (!strcmp(s, \"if\"))\n      return (T_IF);\n    if (!strcmp(s, \"int\"))\n      return (T_INT);\n    break;\n  case 'l':\n    if (!strcmp(s, \"long\"))\n      return (T_LONG);\n    break;\n  case 'r':\n    if (!strcmp(s, \"return\"))\n      return (T_RETURN);\n    break;\n  case 'w':\n    if (!strcmp(s, \"while\"))\n      return (T_WHILE);\n    break;\n  case 'v':\n    if (!strcmp(s, \"void\"))\n      return (T_VOID);\n    break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n  case EOF:\n    t->token = T_EOF;\n    return (0);\n  case '+':\n    if ((c = next()) == '+') {\n      t->token = T_INC;\n    } else {\n      putback(c);\n      t->token = T_PLUS;\n    }\n    break;\n  case '-':\n    if ((c = next()) == '-') {\n      t->token = T_DEC;\n    } else {\n      putback(c);\n      t->token = T_MINUS;\n    }\n    break;\n  case '*':\n    t->token = T_STAR;\n    break;\n  case '/':\n    t->token = T_SLASH;\n    break;\n  case ';':\n    t->token = T_SEMI;\n    break;\n  case '{':\n    t->token = T_LBRACE;\n    break;\n  case '}':\n    t->token = T_RBRACE;\n    break;\n  case '(':\n    t->token = T_LPAREN;\n    break;\n  case ')':\n    t->token = T_RPAREN;\n    break;\n  case '[':\n    t->token = T_LBRACKET;\n    break;\n  case ']':\n    t->token = T_RBRACKET;\n    break;\n  case '~':\n    t->token = T_INVERT;\n    break;\n  case '^':\n    t->token = T_XOR;\n    break;\n  case ',':\n    t->token = T_COMMA;\n    break;\n  case '=':\n    if ((c = next()) == '=') {\n      t->token = T_EQ;\n    } else {\n      putback(c);\n      t->token = T_ASSIGN;\n    }\n    break;\n  case '!':\n    if ((c = next()) == '=') {\n      t->token = T_NE;\n    } else {\n      putback(c);\n      t->token = T_LOGNOT;\n    }\n    break;\n  case '<':\n    if ((c = next()) == '=') {\n      t->token = T_LE;\n    } else if (c == '<') {\n      t->token = T_LSHIFT;\n    } else {\n      putback(c);\n      t->token = T_LT;\n    }\n    break;\n  case '>':\n    if ((c = next()) == '=') {\n      t->token = T_GE;\n    } else if (c == '>') {\n      t->token = T_RSHIFT;\n    } else {\n      putback(c);\n      t->token = T_GT;\n    }\n    break;\n  case '&':\n    if ((c = next()) == '&') {\n      t->token = T_LOGAND;\n    } else {\n      putback(c);\n      t->token = T_AMPER;\n    }\n    break;\n  case '|':\n    if ((c = next()) == '|') {\n      t->token = T_LOGOR;\n    } else {\n      putback(c);\n      t->token = T_OR;\n    }\n    break;\n  case '\\'':\n    // If it's a quote, scan in the\n    // literal character value and\n    // the trailing quote\n    t->intvalue = scanch();\n    t->token = T_INTLIT;\n    if (next() != '\\'')\n      fatal(\"Expected '\\\\'' at end of char literal\");\n    break;\n  case '\"':\n    // Scan in a literal string\n    scanstr(Text);\n    t->token = T_STRLIT;\n    break;\n  default:\n    // If it's a digit, scan the\n    // literal integer value in\n    if (isdigit(c)) {\n      t->intvalue = scanint(c);\n      t->token = T_INTLIT;\n      break;\n    } else if (isalpha(c) || '_' == c) {\n      // Read in a keyword or identifier\n      scanident(c, Text, TEXTLEN);\n\n      // If it's a recognised keyword, return that token\n      if ((tokentype = keyword(Text)) != 0) {\n\tt->token = tokentype;\n\tbreak;\n      }\n      // Not a recognised keyword, so it must be an identifier\n      t->token = T_IDENT;\n      break;\n    }\n    // The character isn't part of any recognised token, error\n    fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Symtable[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Symtable[Functionid].type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n\n    // The beginning of a variable declaration.\n    // Parse the type and get the identifier.\n    // Then parse the rest of the declaration\n    // and skip over the semicolon\n    type = parse_type();\n    ident();\n    var_declaration(type, C_LOCAL);\n    semi();\n    return (NULL);\t\t// No AST generated here\n  case T_IF:\n    return (if_statement());\n  case T_WHILE:\n    return (while_statement());\n  case T_FOR:\n    return (for_statement());\n  case T_RETURN:\n    return (return_statement());\n  default:\n    // For now, see if this is an expression.\n    // This catches assignment statements.\n    return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "28_Runtime_Flags/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\n// Skip C_PARAM entries\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (Symtable[i].class == C_PARAM)\n      continue;\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= Locls)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return its slot position or -1 if not found.\nint findlocl(char *s) {\n  int i;\n\n  for (i = Locls + 1; i < NSYMBOLS; i++) {\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new local symbol slot, or die\n// if we've run out of positions.\nstatic int newlocl(void) {\n  int p;\n\n  if ((p = Locls--) <= Globs)\n    fatal(\"Too many local symbols\");\n  return (p);\n}\n\n// Clear all the entries in the\n// local symbol table\nvoid freeloclsyms(void) {\n  Locls = NSYMBOLS - 1;\n}\n\n// Update a symbol at the given slot number in the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// + endlabel: if this is a function\n// + posn: Position information for local symbols\nstatic void updatesym(int slot, char *name, int type, int stype,\n\t\t      int class, int endlabel, int size, int posn) {\n  if (slot < 0 || slot >= NSYMBOLS)\n    fatal(\"Invalid symbol slot number in updatesym()\");\n  Symtable[slot].name = strdup(name);\n  Symtable[slot].type = type;\n  Symtable[slot].stype = stype;\n  Symtable[slot].class = class;\n  Symtable[slot].endlabel = endlabel;\n  Symtable[slot].size = size;\n  Symtable[slot].posn = posn;\n}\n\n// Add a global symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + class of the symbol\n// + size: number of elements\n// + endlabel: if this is a function\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int class, int endlabel,\n\t    int size) {\n  int slot;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((slot = findglob(name)) != -1)\n    return (slot);\n\n  // Otherwise get a new slot and fill it in\n  slot = newglob();\n  updatesym(slot, name, type, stype, class, endlabel, size, 0);\n  // Generate the assembly for the symbol if it's global\n  if (class == C_GLOBAL)\n    genglobsym(slot);\n  // Return the slot number\n  return (slot);\n}\n\n// Add a local symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// Return the slot number in the symbol table, -1 if a duplicate entry\nint addlocl(char *name, int type, int stype, int class, int size) {\n  int localslot;\n\n  // If this is already in the symbol table, return an error\n  if ((localslot = findlocl(name)) != -1)\n    return (-1);\n\n  // Otherwise get a new symbol slot and a position for this local.\n  // Update the local symbol table entry.\n  localslot = newlocl();\n  updatesym(localslot, name, type, stype, class, 0, size, 0);\n\n  // Return the local symbol's slot\n  return (localslot);\n}\n\n// Given a function's slot number, copy the global parameters\n// from its prototype to be local parameters\nvoid copyfuncparams(int slot) {\n  int i, id = slot + 1;\n\n  for (i = 0; i < Symtable[slot].nelems; i++, id++) {\n    addlocl(Symtable[id].name, Symtable[id].type, Symtable[id].stype,\n\t    Symtable[id].class, Symtable[id].size);\n  }\n}\n\n\n// Determine if the symbol s is in the symbol table.\n// Return its slot position or -1 if not found.\nint findsymbol(char *s) {\n  int slot;\n\n  slot = findlocl(s);\n  if (slot == -1)\n    slot = findglob(s);\n  return (slot);\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globs = 0;\n  Locls = NSYMBOLS - 1;\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:15 on line 5\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input32.c",
    "content": "Unknown variable:cow on line 4\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input33.c",
    "content": "Incompatible type to return on line 4\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input34.c",
    "content": "For now, declaration of local arrays is not implemented on line 4\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 4\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:3 on line 4\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input37.c",
    "content": "Unexpected token in parameter list:15 on line 3\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:3 on line 4\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 4\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input40.c",
    "content": "No return for function with non-void type on line 4\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input41.c",
    "content": "Can't return from a void function on line 3\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input42.c",
    "content": "Undeclared function:fred on line 3\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input43.c",
    "content": "Undeclared array:b on line 3\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input44.c",
    "content": "Unknown variable:z on line 3\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 3\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 6\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 6\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 4\n"
  },
  {
    "path": "28_Runtime_Flags/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 5\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input01.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input02.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input03.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input04.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input05.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input06.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input07.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input08.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input09.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input10.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input11.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input12.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input13.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input14.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input15.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input16.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input17.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input18.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input18a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input19.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input20.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input21.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input22.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input23.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input24.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input25.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input26.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input27.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input28.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input29.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input31.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input32.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input33.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input34.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input35.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input36.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input37.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input38.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input39.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input40.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input41.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input42.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input43.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input44.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input45.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input46.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input47.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input48.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input49.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input50.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input51.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input52.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i ../lib/printint.c\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "28_Runtime_Flags/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "28_Runtime_Flags/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "28_Runtime_Flags/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "28_Runtime_Flags/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->v.intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n  case A_IF:\n    Lfalse = gendumplabel();\n    for (int i = 0; i < level; i++)\n      fprintf(stdout, \" \");\n    fprintf(stdout, \"A_IF\");\n    if (n->right) {\n      Lend = gendumplabel();\n      fprintf(stdout, \", end L%d\", Lend);\n    }\n    fprintf(stdout, \"\\n\");\n    dumpAST(n->left, Lfalse, level + 2);\n    dumpAST(n->mid, NOLABEL, level + 2);\n    if (n->right)\n      dumpAST(n->right, NOLABEL, level + 2);\n    return;\n  case A_WHILE:\n    Lstart = gendumplabel();\n    for (int i = 0; i < level; i++)\n      fprintf(stdout, \" \");\n    fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n    Lend = gendumplabel();\n    dumpAST(n->left, Lend, level + 2);\n    dumpAST(n->right, NOLABEL, level + 2);\n    return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n  case A_GLUE:\n    fprintf(stdout, \"\\n\\n\");\n    return;\n  case A_FUNCTION:\n    fprintf(stdout, \"A_FUNCTION %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_ADD:\n    fprintf(stdout, \"A_ADD\\n\");\n    return;\n  case A_SUBTRACT:\n    fprintf(stdout, \"A_SUBTRACT\\n\");\n    return;\n  case A_MULTIPLY:\n    fprintf(stdout, \"A_MULTIPLY\\n\");\n    return;\n  case A_DIVIDE:\n    fprintf(stdout, \"A_DIVIDE\\n\");\n    return;\n  case A_EQ:\n    fprintf(stdout, \"A_EQ\\n\");\n    return;\n  case A_NE:\n    fprintf(stdout, \"A_NE\\n\");\n    return;\n  case A_LT:\n    fprintf(stdout, \"A_LE\\n\");\n    return;\n  case A_GT:\n    fprintf(stdout, \"A_GT\\n\");\n    return;\n  case A_LE:\n    fprintf(stdout, \"A_LE\\n\");\n    return;\n  case A_GE:\n    fprintf(stdout, \"A_GE\\n\");\n    return;\n  case A_INTLIT:\n    fprintf(stdout, \"A_INTLIT %d\\n\", n->v.intvalue);\n    return;\n  case A_STRLIT:\n    fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->v.id);\n    return;\n  case A_IDENT:\n    if (n->rvalue)\n      fprintf(stdout, \"A_IDENT rval %s\\n\", Symtable[n->v.id].name);\n    else\n      fprintf(stdout, \"A_IDENT %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_ASSIGN:\n    fprintf(stdout, \"A_ASSIGN\\n\");\n    return;\n  case A_WIDEN:\n    fprintf(stdout, \"A_WIDEN\\n\");\n    return;\n  case A_RETURN:\n    fprintf(stdout, \"A_RETURN\\n\");\n    return;\n  case A_FUNCCALL:\n    fprintf(stdout, \"A_FUNCCALL %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_ADDR:\n    fprintf(stdout, \"A_ADDR %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_DEREF:\n    if (n->rvalue)\n      fprintf(stdout, \"A_DEREF rval\\n\");\n    else\n      fprintf(stdout, \"A_DEREF\\n\");\n    return;\n  case A_SCALE:\n    fprintf(stdout, \"A_SCALE %d\\n\", n->v.size);\n    return;\n  case A_PREINC:\n    fprintf(stdout, \"A_PREINC %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_PREDEC:\n    fprintf(stdout, \"A_PREDEC %s\\n\", Symtable[n->v.id].name);\n    return;\n  case A_POSTINC:\n    fprintf(stdout, \"A_POSTINC\\n\");\n    return;\n  case A_POSTDEC:\n    fprintf(stdout, \"A_POSTDEC\\n\");\n    return;\n  case A_NEGATE:\n    fprintf(stdout, \"A_NEGATE\\n\");\n    return;\n  default:\n    fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "28_Runtime_Flags/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  if (type == P_CHAR || type == P_INT || type == P_LONG)\n    return (1);\n  return (0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  if (type == P_VOIDPTR || type == P_CHARPTR ||\n      type == P_INTPTR || type == P_LONGPTR)\n    return (1);\n  return (0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  int newtype;\n  switch (type) {\n  case P_VOID:\n    newtype = P_VOIDPTR;\n    break;\n  case P_CHAR:\n    newtype = P_CHARPTR;\n    break;\n  case P_INT:\n    newtype = P_INTPTR;\n    break;\n  case P_LONG:\n    newtype = P_LONGPTR;\n    break;\n  default:\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  }\n  return (newtype);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  int newtype;\n  switch (type) {\n  case P_VOIDPTR:\n    newtype = P_VOID;\n    break;\n  case P_CHARPTR:\n    newtype = P_CHAR;\n    break;\n  case P_INTPTR:\n    newtype = P_INT;\n    break;\n  case P_LONGPTR:\n    newtype = P_LONG;\n    break;\n  default:\n    fatald(\"Unrecognised in value_at: type\", type);\n  }\n  return (newtype);\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "29_Refactoring/Makefile",
    "content": "HSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out\n\ntest: cwj tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "29_Refactoring/Readme.md",
    "content": "# Part 29: A Bit of Refactoring\n\nI started thinking about the design side of implementing structs, unions\nand enums in our compiler, and then I had a good idea on how to improve\nthe symbol table, and that led me to doing a bit of refactoring of the\ncompiler's code. So in this part of the journey there is no new functionality,\nbut I feel a bit happier about some of the code in the compiler.\n\nIf you are more interested in my design ideas for structs, unions\nand enums, feel free to skip to the next part.\n\n## Refactoring the Symbol Table\n\nWhen I started writing our compiler, I had just finished reading through\nthe [SubC](http://www.t3x.org/subc/) compiler's code and adding my own\ncomments. Thus, I borrowed many of my initial ideas from this code base.\nOne of them was to have an array of elements for the symbol table, with\nglobal symbols at one end and local symbols at the other.\n\nWe've seen, for function prototypes and parameters, that we have to copy\na function's prototype from the global end over to the local end so that\nthe function has local parameter variables. And we have to worry if\none end of the symbol table crashes into the other end.\n\nSo, at some point, we should convert the symbol table into a number of\nsingly-linked lists: at least one for the global symbols and one for the\nlocal symbols. When we get to implementing enums, I might have a third one\nfor the enum values.\n\nNow, I haven't done this refactoring in this part of the journey as the\nchanges look to be substantial, so I'll wait until I really need to do it.\nBut one more change I will make is this. Each symbol node will have a `next`\npointer to form the singly-linked list, but also a `param` pointer. This\nwill allow functions to have a separate singly-linked list for their\nparameters which we can skip past when searching for global symbols.\nThen, when we need to \"copy\" a function's prototype to be its list of\nparameters, we can simply copy the pointer to the prototype list of parameters.\nAnyway, this change is for the future.\n\n## Types, Revisited\n\nAnother thing that I borrowed from SubC is the enumeration of types\n(in `defs.h`):\n\n```c\n// Primitive types\nenum {\n  P_NONE, P_VOID, P_CHAR, P_INT, P_LONG,\n  P_VOIDPTR, P_CHARPTR, P_INTPTR, P_LONGPTR\n};\n```\n\nSubC only allows one level of indirection, thus the list of types above.\nI had the idea, why not encode the level of indirection in the primitive type\nvalue? So I've changed our code so that the bottom four bits in a `type`\ninteger is the level of indirection, and the higher bits encode the\nactual type:\n\n```c\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID=16, P_CHAR=32, P_INT=48, P_LONG=64\n};\n```\n\nI've been able to completely refactor out all of the old `P_XXXPTR`\nreferences in the old code. Let's see what changes there have been.\n\nFirstly, we have to deal with scalar and pointer types in `types.c`. The code\nnow is actually smaller than before:\n\n```c\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return ((type & 0xf) == 0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n```\n\nAnd `modify_type()` hasn't changed whatsoever.\n\nIn `expr.c`, when dealing with literal strings, I was using `P_CHARPTR`\nbut now I can write:\n\n```c\n   n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), id);\n```\n\nOne other substantial area where the `P_XXXPTR` values were used is the code\nin the hardware-dependent code in `cg.c`. We start by rewriting `cgprimsize()`\nto use `ptrtype()`:\n\n```c\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type)) return (8);\n  switch (type) {\n    case P_CHAR: return (1);\n    case P_INT:  return (4);\n    case P_LONG: return (8);\n    default: fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);                   // Keep -Wall happy\n}\n```\n\nWith this code, the other functions in `cg.c` can\nnow call `cgprimsize()`, `ptrtype()`,\n`inttype()`, `pointer_to()` and `value_at()` as required, instead of\nreferring to specific types. Here's an example from `cg.c`:\n\n```c\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 2:\n    fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 4:\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  default:\n    fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n```\n\nHave a quick read through `cg.c` and look for the calls to `cgprimsize()`.\n\n### An Example Use of Double Pointers\n\nNow that we have up to sixteen levels of indirection, I wrote a test program\nto confirm that they work, `tests/input55.c`:\n\n```c\nint printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n```\n\nNote that `argv++` doesn't yet work, and `argv[i]` also doesn't yet work.\nBut we can work around these missing features as shown above.\n\n## Changes to the Symbol Table Structure\n\nWhile I didn't refactor the symbol table into lists, I did tweak the\nsymbol table structure itself, now that I realised that I can use\nunions and not have to give the union a variable name:\n\n```c\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  union {\n    int size;                   // Number of elements in the symbol\n    int endlabel;               // For functions, the end label\n  };\n  union {\n    int nelems;                 // For functions, # of params\n    int posn;                   // For locals, the negative offset\n                                // from the stack base pointer\n  };\n};\n```\n\nI used to have a `#define` for `nelems`, but the above is the same result and\nprevents the global definition of `nelems` from polluting the namespace. I\nalso realised that `size` and `endlabel` could occupy the same position in the\nstructure, and added that union. There are a few cosmetic changes to the\nparameters to `addglob()`, but not much else.\n\n## Changes to the AST Structure\n\nSimilarly, I've modified the AST node structure so that the union doesn't\nhave a variable name:\n\n```c\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {                       // For A_INTLIT, the integer value\n    int intvalue;               // For A_IDENT, the symbol slot number\n    int id;                     // For A_FUNCTION, the symbol slot number\n    int size;                   // For A_SCALE, the size to scale by\n  };                            // For A_FUNCCALL, the symbol slot number\n};\n```\n\nand this means that I can, e.g., write the second line instead of the first\none:\n\n```c\n    return (cgloadglob(n->left->v.id, n->op));    // Old code\n    return (cgloadglob(n->left->id,   n->op));    // New code\n```\n## Conclusion and What's Next\n\nThat's about it for this part of our compiler writing journey. I might\nhave done a few more small code changes here and there, but I can't\nthink of anything else that was major.\n\nI will get to changing the symbol table to be a linked list; this will\nprobably happen in the part where we implement enumerated values.\n\nIn the next part of our compiler writing journey, I'll get back to\nwhat I wanted to cover in this part: the design side of implementing\nstructs, unions and enums in our compiler. [Next step](../30_Design_Composites/Readme.md)\n"
  },
  {
    "path": "29_Refactoring/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  int i;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack\n  // Stop after no more than six parameter registers\n  for (i = NSYMBOLS - 1; i > Locls; i--) {\n    if (Symtable[i].class != C_PARAM)\n      break;\n    if (i < NSYMBOLS - 6)\n      break;\n    Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    cgstorlocal(paramReg--, i);\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (; i > Locls; i--) {\n    if (Symtable[i].class == C_PARAM) {\n      Symtable[i].posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    }\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(Symtable[id].type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", Symtable[id].name);\n  } else\n    // Print out the code to initialise it\n    switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", Symtable[id].name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(Symtable[id].type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", Symtable[id].posn);\n  } else\n    switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t      reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", Symtable[id].posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", id, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(int id, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", Symtable[id].name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  if (cgprimsize(Symtable[id].type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r],\n\t    Symtable[id].name);\n  } else\n    switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r],\n\t      Symtable[id].name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r],\n\t      Symtable[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n\n  if (cgprimsize(Symtable[id].type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r],\n\t    Symtable[id].posn);\n  } else\n    switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r],\n\t      Symtable[id].posn);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r],\n\t      Symtable[id].posn);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n    }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n  case P_CHAR:\n    return (1);\n  case P_INT:\n    return (4);\n  case P_LONG:\n    return (8);\n  default:\n    fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n    break;\n  case P_INT:\n    fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n    break;\n  case P_LONG:\n    fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n    break;\n  default:\n    fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", Symtable[id].name,\n\t    reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", Symtable[id].posn,\n\t    reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 2:\n    fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 4:\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  default:\n    fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n    break;\n  case 2:\n  case 4:\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "29_Refactoring/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  case P_INT:\n  case P_LONG:\n  case P_CHARPTR:\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n    break;\n  default:\n    fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n  case P_CHAR:\n    return (1);\n  case P_INT:\n  case P_LONG:\n    return (4);\n  default:\n    fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n  case 1:\n    fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n    break;\n  case 4:\n    fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n    break;\n  default:\n    fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n  case P_CHARPTR:\n    fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  case P_INTPTR:\n  case P_LONGPTR:\n    fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n    break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n  case P_CHAR:\n    fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n    break;\n  case P_INT:\n  case P_LONG:\n    fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "29_Refactoring/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  int i;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack\n  // Stop after no more than six parameter registers\n  for (i = NSYMBOLS - 1; i > Locls; i--) {\n    if (Symtable[i].class != C_PARAM)\n      break;\n    if (i < NSYMBOLS - 6)\n      break;\n    Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    cgstorlocal(paramReg--, i);\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (; i > Locls; i--) {\n    if (Symtable[i].class == C_PARAM) {\n      Symtable[i].posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      Symtable[i].posn = newlocaloffset(Symtable[i].type);\n    }\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(Symtable[id].type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], Symtable[id].name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", Symtable[id].name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", Symtable[id].name);\n  } else\n  // Print out the code to initialise it\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              Symtable[id].name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", Symtable[id].name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              Symtable[id].name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", Symtable[id].name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(int id, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(Symtable[id].type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            Symtable[id].posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", Symtable[id].posn);\n  } else\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              Symtable[id].posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n              Symtable[id].posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", Symtable[id].posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int id) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], id);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(int id, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", Symtable[id].name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n  if (cgprimsize(Symtable[id].type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, reglist[r]);\n  } else\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", Symtable[id].name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, int id) {\n  if (cgprimsize(Symtable[id].type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n            reglist[r]);\n  } else\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", Symtable[id].posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(int id) {\n  int typesize;\n  if (Symtable[id].stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"%s:\", Symtable[id].name);\n\n  // Generate the space\n  // original version\n  for (int i = 0; i < Symtable[id].size; i++) {\n    switch(typesize) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(typesize) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", Symtable[id].size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", Symtable[id].size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", Symtable[id].size);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  // Generate code depending on the function's type\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", Symtable[id].type);\n  }\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  int r = alloc_register();\n\n  if (Symtable[id].class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], Symtable[id].name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            Symtable[id].posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "29_Refactoring/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t// Current line number\nextern_ int Putback;\t\t// Character put back by scanner\nextern_ int Functionid;\t\t// Symbol id of the current function\nextern_ int Globs;\t\t// Position of next free global symbol slot\nextern_ int Locls;\t\t// Position of next free local symbol slot\nextern_ FILE *Infile;\t\t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Outfilename;\t// Name of file we opened as Outfile\nextern_ struct token Token;\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t// Last identifier scanned\nextern_ struct symtable Symtable[NSYMBOLS];\t// Global symbol table\n\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "29_Refactoring/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n  case T_VOID:\n    type = P_VOID;\n    break;\n  case T_CHAR:\n    type = P_CHAR;\n    break;\n  case T_INT:\n    type = P_INT;\n    break;\n  case T_LONG:\n    type = P_LONG;\n    break;\n  default:\n    fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type.\n// class is the variable's class\nvoid var_declaration(int type, int class) {\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      if (class == C_LOCAL) {\n\tfatal(\"For now, declaration of local arrays is not implemented\");\n      } else {\n\taddglob(Text, pointer_to(type), S_ARRAY, class, Token.intvalue);\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    if (class == C_LOCAL) {\n      if (addlocl(Text, type, S_VARIABLE, class, 1) == -1)\n\tfatals(\"Duplicate local variable declaration\", Text);\n    } else {\n      addglob(Text, type, S_VARIABLE, class, 1);\n    }\n  }\n}\n\n// param_declaration: <null>\n//           | variable_declaration\n//           | variable_declaration ',' param_declaration\n//\n// Parse the parameters in parentheses after the function name.\n// Add them as symbols to the symbol table and return the number\n// of parameters. If id is not -1, there is an existing function\n// prototype, and the function has this symbol slot number.\nstatic int param_declaration(int id) {\n  int type, param_id;\n  int orig_paramcnt;\n  int paramcnt = 0;\n\n  // Add 1 to id so that it's either zero (no prototype), or\n  // it's the position of the zeroth existing parameter in\n  // the symbol table\n  param_id = id + 1;\n\n  // Get any existing prototype parameter count\n  if (param_id)\n    orig_paramcnt = Symtable[id].nelems;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n    // Get the type and identifier\n    // and add it to the symbol table\n    type = parse_type();\n    ident();\n\n    // We have an existing prototype.\n    // Check that this type matches the prototype.\n    if (param_id) {\n      if (type != Symtable[id].type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      param_id++;\n    } else {\n      // Add a new parameter to the new prototype\n      var_declaration(type, C_PARAM);\n    }\n    paramcnt++;\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in parameter list\", Token.token);\n    }\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((id != -1) && (paramcnt != orig_paramcnt))\n    fatals(\"Parameter count mismatch for function\", Symtable[id].name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  int id;\n  int nameslot, endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set id to -1\n  if ((id = findsymbol(Text)) != -1)\n    if (Symtable[id].stype != S_FUNCTION)\n      id = -1;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (id == -1) {\n    endlabel = genlabel();\n    nameslot = addglob(Text, type, S_FUNCTION, C_GLOBAL, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype symbol slot number\n  lparen();\n  paramcnt = param_declaration(id);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters\n  if (id == -1)\n    Symtable[nameslot].nelems = paramcnt;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n  // This is not just a prototype.\n  // Copy the global parameters to be local parameters\n  if (id == -1)\n    id = nameslot;\n  copyfuncparams(id);\n\n  // Set the Functionid global to the function's symbol-id\n  Functionid = id;\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's id\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, id));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration\n      tree = function_declaration(type);\n\n      // Only a function prototype, no code\n      if (tree == NULL)\n\tcontinue;\n\n      // A real function, generate the assembly code for it\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, C_GLOBAL);\n      semi();\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "29_Refactoring/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t    struct ASTnode *left, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(int id);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(int id);\nvoid cgfuncpostamble(int id);\nint cgloadint(int value, int type);\nint cgloadglob(int id, int op);\nint cgloadlocal(int id, int op);\nint cgloadglobstr(int id);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(int id, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, int id);\nint cgstorlocal(int r, int id);\nvoid cgglobsym(int id);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, int id);\nint cgaddress(int id);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nint findglob(char *s);\nint findlocl(char *s);\nint findsymbol(char *s);\nint addglob(char *name, int type, int stype, int class, int size);\nint addlocl(char *name, int type, int stype, int class, int size);\nvoid copyfuncparams(int slot);\nvoid freeloclsyms(void);\nvoid clear_symtable(void);\n\n// decl.c\nvoid var_declaration(int type, int class);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint parse_type(void);\nint pointer_to(int type);\nint value_at(int type);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "29_Refactoring/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN=512,\t\t\t// Length of symbols in input\n  NSYMBOLS=1024\t\t\t// Number of symbol table entries\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND, \n  T_OR, T_XOR, T_AMPER, \n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN= 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID=16, P_CHAR=32, P_INT=48, P_LONG=64\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  union {\t\t\t// For A_INTLIT, the integer value\n    int intvalue;\t\t// For A_IDENT, the symbol slot number\n    int id;\t\t\t// For A_FUNCTION, the symbol slot number\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\t\t\t\t// For A_FUNCCALL, the symbol slot number\n};\n\nenum {\n  NOREG= -1,\t\t\t// Use NOREG when the AST generation\n\t\t\t\t// functions have no register to return\n  NOLABEL=  0\t\t\t// Use NOLABEL when we have no label to\n\t\t\t\t// pass to genAST()\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n        C_GLOBAL = 1,\t\t// Globally visible symbol\n        C_LOCAL,\t\t// Locally visible symbol\n        C_PARAM\t\t\t// Locally visible function parameter\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  union {\n    int size;\t\t\t// Number of elements in the symbol\n    int endlabel;\t\t// For functions, the end label\n  };\n  union {\n    int nelems;\t\t\t// For functions, # of params\n    int posn;\t\t\t// For locals, the negative offset\n\t\t\t\t// from the stack base pointer\n  };\n};\n"
  },
  {
    "path": "29_Refactoring/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  int id;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, Symtable[id].type, tree, id);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  int id;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((id = findsymbol(Text)) == -1 || Symtable[id].stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, Symtable[id].type, id);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, Symtable[id].type, left, NULL, right, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  int id;\n\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // A variable. Check that the variable exists.\n  id = findsymbol(Text);\n  if (id == -1 || Symtable[id].stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, Symtable[id].type, id);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, Symtable[id].type, id);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, Symtable[id].type, id);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left = mkastnode(binastop(tokentype), left->type, left, NULL, right, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "29_Refactoring/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->id, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n  case A_IF:\n    return (genIF(n));\n  case A_WHILE:\n    return (genWHILE(n));\n  case A_FUNCCALL:\n    return (gen_funccall(n));\n  case A_GLUE:\n    // Do each child statement, and free the\n    // registers after each child\n    genAST(n->left, NOLABEL, n->op);\n    genfreeregs();\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    return (NOREG);\n  case A_FUNCTION:\n    // Generate the function's preamble before the code\n    // in the child sub-tree\n    cgfuncpreamble(n->id);\n    genAST(n->left, NOLABEL, n->op);\n    cgfuncpostamble(n->id);\n    return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n  case A_ADD:\n    return (cgadd(leftreg, rightreg));\n  case A_SUBTRACT:\n    return (cgsub(leftreg, rightreg));\n  case A_MULTIPLY:\n    return (cgmul(leftreg, rightreg));\n  case A_DIVIDE:\n    return (cgdiv(leftreg, rightreg));\n  case A_AND:\n    return (cgand(leftreg, rightreg));\n  case A_OR:\n    return (cgor(leftreg, rightreg));\n  case A_XOR:\n    return (cgxor(leftreg, rightreg));\n  case A_LSHIFT:\n    return (cgshl(leftreg, rightreg));\n  case A_RSHIFT:\n    return (cgshr(leftreg, rightreg));\n  case A_EQ:\n  case A_NE:\n  case A_LT:\n  case A_GT:\n  case A_LE:\n  case A_GE:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, compare registers\n    // and set one to 1 or 0 based on the comparison.\n    if (parentASTop == A_IF || parentASTop == A_WHILE)\n      return (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n    else\n      return (cgcompare_and_set(n->op, leftreg, rightreg));\n  case A_INTLIT:\n    return (cgloadint(n->intvalue, n->type));\n  case A_STRLIT:\n    return (cgloadglobstr(n->id));\n  case A_IDENT:\n    // Load our value if we are an rvalue\n    // or we are being dereferenced\n    if (n->rvalue || parentASTop == A_DEREF) {\n      if (Symtable[n->id].class == C_GLOBAL) {\n\treturn (cgloadglob(n->id, n->op));\n      } else {\n\treturn (cgloadlocal(n->id, n->op));\n      }\n    } else\n      return (NOREG);\n  case A_ASSIGN:\n    // Are we assigning to an identifier or through a pointer?\n    switch (n->right->op) {\n    case A_IDENT:\n      if (Symtable[n->right->id].class == C_GLOBAL)\n\treturn (cgstorglob(leftreg, n->right->id));\n      else\n\treturn (cgstorlocal(leftreg, n->right->id));\n    case A_DEREF:\n      return (cgstorderef(leftreg, rightreg, n->right->type));\n    default:\n      fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n    }\n  case A_WIDEN:\n    // Widen the child's type to the parent's type\n    return (cgwiden(leftreg, n->left->type, n->type));\n  case A_RETURN:\n    cgreturn(leftreg, Functionid);\n    return (NOREG);\n  case A_ADDR:\n    return (cgaddress(n->id));\n  case A_DEREF:\n    // If we are an rvalue, dereference to get the value we point at,\n    // otherwise leave it for A_ASSIGN to store through the pointer\n    if (n->rvalue)\n      return (cgderef(leftreg, n->left->type));\n    else\n      return (leftreg);\n  case A_SCALE:\n    // Small optimisation: use shift if the\n    // scale value is a known power of two\n    switch (n->size) {\n    case 2:\n      return (cgshlconst(leftreg, 1));\n    case 4:\n      return (cgshlconst(leftreg, 2));\n    case 8:\n      return (cgshlconst(leftreg, 3));\n    default:\n      // Load a register with the size and\n      // multiply the leftreg by this size\n      rightreg = cgloadint(n->size, P_INT);\n      return (cgmul(leftreg, rightreg));\n    }\n  case A_POSTINC:\n  case A_POSTDEC:\n    // Load and decrement the variable's value into a register\n    // and post increment/decrement it\n    if (Symtable[n->id].class == C_GLOBAL)\n      return (cgloadglob(n->id, n->op));\n    else\n      return (cgloadlocal(n->id, n->op));\n  case A_PREINC:\n  case A_PREDEC:\n    // Load and decrement the variable's value into a register\n    // and pre increment/decrement it\n    if (Symtable[n->left->id].class == C_GLOBAL)\n      return (cgloadglob(n->left->id, n->op));\n    else\n      return (cgloadlocal(n->left->id, n->op));\n  case A_NEGATE:\n    return (cgnegate(leftreg));\n  case A_INVERT:\n    return (cginvert(leftreg));\n  case A_LOGNOT:\n    return (cglognot(leftreg));\n  case A_TOBOOL:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, set the register\n    // to 0 or 1 based on it's zeroeness or non-zeroeness\n    return (cgboolean(leftreg, parentASTop, label));\n  default:\n    fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(int id) {\n  cgglobsym(id);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "29_Refactoring/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Open up the input file\n  if ((Infile = fopen(filename, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ= 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n      case 'o':\n\toutfilename = argv[++i];\t// Save & skip to next argument\n\tbreak;\n      case 'T':\n\tO_dumpAST = 1;\n\tbreak;\n      case 'c':\n\tO_assemble = 1;\n\tO_keepasm = 0;\n\tO_dolink = 0;\n\tbreak;\n      case 'S':\n\tO_keepasm = 1;\n\tO_assemble = 0;\n\tO_dolink = 0;\n\tbreak;\n      case 'v':\n\tO_verbose = 1;\n\tbreak;\n      default:\n\tusage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "29_Refactoring/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "29_Refactoring/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n    case 'a':\n      return '\\a';\n    case 'b':\n      return '\\b';\n    case 'f':\n      return '\\f';\n    case 'n':\n      return '\\n';\n    case 'r':\n      return '\\r';\n    case 't':\n      return '\\t';\n    case 'v':\n      return '\\v';\n    case '\\\\':\n      return '\\\\';\n    case '\"':\n      return '\"';\n    case '\\'':\n      return '\\'';\n    default:\n      fatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n  case 'c':\n    if (!strcmp(s, \"char\"))\n      return (T_CHAR);\n    break;\n  case 'e':\n    if (!strcmp(s, \"else\"))\n      return (T_ELSE);\n    break;\n  case 'f':\n    if (!strcmp(s, \"for\"))\n      return (T_FOR);\n    break;\n  case 'i':\n    if (!strcmp(s, \"if\"))\n      return (T_IF);\n    if (!strcmp(s, \"int\"))\n      return (T_INT);\n    break;\n  case 'l':\n    if (!strcmp(s, \"long\"))\n      return (T_LONG);\n    break;\n  case 'r':\n    if (!strcmp(s, \"return\"))\n      return (T_RETURN);\n    break;\n  case 'w':\n    if (!strcmp(s, \"while\"))\n      return (T_WHILE);\n    break;\n  case 'v':\n    if (!strcmp(s, \"void\"))\n      return (T_VOID);\n    break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n  case EOF:\n    t->token = T_EOF;\n    return (0);\n  case '+':\n    if ((c = next()) == '+') {\n      t->token = T_INC;\n    } else {\n      putback(c);\n      t->token = T_PLUS;\n    }\n    break;\n  case '-':\n    if ((c = next()) == '-') {\n      t->token = T_DEC;\n    } else {\n      putback(c);\n      t->token = T_MINUS;\n    }\n    break;\n  case '*':\n    t->token = T_STAR;\n    break;\n  case '/':\n    t->token = T_SLASH;\n    break;\n  case ';':\n    t->token = T_SEMI;\n    break;\n  case '{':\n    t->token = T_LBRACE;\n    break;\n  case '}':\n    t->token = T_RBRACE;\n    break;\n  case '(':\n    t->token = T_LPAREN;\n    break;\n  case ')':\n    t->token = T_RPAREN;\n    break;\n  case '[':\n    t->token = T_LBRACKET;\n    break;\n  case ']':\n    t->token = T_RBRACKET;\n    break;\n  case '~':\n    t->token = T_INVERT;\n    break;\n  case '^':\n    t->token = T_XOR;\n    break;\n  case ',':\n    t->token = T_COMMA;\n    break;\n  case '=':\n    if ((c = next()) == '=') {\n      t->token = T_EQ;\n    } else {\n      putback(c);\n      t->token = T_ASSIGN;\n    }\n    break;\n  case '!':\n    if ((c = next()) == '=') {\n      t->token = T_NE;\n    } else {\n      putback(c);\n      t->token = T_LOGNOT;\n    }\n    break;\n  case '<':\n    if ((c = next()) == '=') {\n      t->token = T_LE;\n    } else if (c == '<') {\n      t->token = T_LSHIFT;\n    } else {\n      putback(c);\n      t->token = T_LT;\n    }\n    break;\n  case '>':\n    if ((c = next()) == '=') {\n      t->token = T_GE;\n    } else if (c == '>') {\n      t->token = T_RSHIFT;\n    } else {\n      putback(c);\n      t->token = T_GT;\n    }\n    break;\n  case '&':\n    if ((c = next()) == '&') {\n      t->token = T_LOGAND;\n    } else {\n      putback(c);\n      t->token = T_AMPER;\n    }\n    break;\n  case '|':\n    if ((c = next()) == '|') {\n      t->token = T_LOGOR;\n    } else {\n      putback(c);\n      t->token = T_OR;\n    }\n    break;\n  case '\\'':\n    // If it's a quote, scan in the\n    // literal character value and\n    // the trailing quote\n    t->intvalue = scanch();\n    t->token = T_INTLIT;\n    if (next() != '\\'')\n      fatal(\"Expected '\\\\'' at end of char literal\");\n    break;\n  case '\"':\n    // Scan in a literal string\n    scanstr(Text);\n    t->token = T_STRLIT;\n    break;\n  default:\n    // If it's a digit, scan the\n    // literal integer value in\n    if (isdigit(c)) {\n      t->intvalue = scanint(c);\n      t->token = T_INTLIT;\n      break;\n    } else if (isalpha(c) || '_' == c) {\n      // Read in a keyword or identifier\n      scanident(c, Text, TEXTLEN);\n\n      // If it's a recognised keyword, return that token\n      if ((tokentype = keyword(Text)) != 0) {\n\tt->token = tokentype;\n\tbreak;\n      }\n      // Not a recognised keyword, so it must be an identifier\n      t->token = T_IDENT;\n      break;\n    }\n    // The character isn't part of any recognised token, error\n    fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "29_Refactoring/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Symtable[Functionid].type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Symtable[Functionid].type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n\n    // The beginning of a variable declaration.\n    // Parse the type and get the identifier.\n    // Then parse the rest of the declaration\n    // and skip over the semicolon\n    type = parse_type();\n    ident();\n    var_declaration(type, C_LOCAL);\n    semi();\n    return (NULL);\t\t// No AST generated here\n  case T_IF:\n    return (if_statement());\n  case T_WHILE:\n    return (while_statement());\n  case T_FOR:\n    return (for_statement());\n  case T_RETURN:\n    return (return_statement());\n  default:\n    // For now, see if this is an expression.\n    // This catches assignment statements.\n    return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "29_Refactoring/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Determine if the symbol s is in the global symbol table.\n// Return its slot position or -1 if not found.\n// Skip C_PARAM entries\nint findglob(char *s) {\n  int i;\n\n  for (i = 0; i < Globs; i++) {\n    if (Symtable[i].class == C_PARAM)\n      continue;\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new global symbol slot, or die\n// if we've run out of positions.\nstatic int newglob(void) {\n  int p;\n\n  if ((p = Globs++) >= Locls)\n    fatal(\"Too many global symbols\");\n  return (p);\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return its slot position or -1 if not found.\nint findlocl(char *s) {\n  int i;\n\n  for (i = Locls + 1; i < NSYMBOLS; i++) {\n    if (*s == *Symtable[i].name && !strcmp(s, Symtable[i].name))\n      return (i);\n  }\n  return (-1);\n}\n\n// Get the position of a new local symbol slot, or die\n// if we've run out of positions.\nstatic int newlocl(void) {\n  int p;\n\n  if ((p = Locls--) <= Globs)\n    fatal(\"Too many local symbols\");\n  return (p);\n}\n\n// Clear all the entries in the\n// local symbol table\nvoid freeloclsyms(void) {\n  Locls = NSYMBOLS - 1;\n}\n\n// Update a symbol at the given slot number in the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\nstatic void updatesym(int slot, char *name, int type, int stype,\n\t\t      int class, int size, int posn) {\n  if (slot < 0 || slot >= NSYMBOLS)\n    fatal(\"Invalid symbol slot number in updatesym()\");\n  Symtable[slot].name = strdup(name);\n  Symtable[slot].type = type;\n  Symtable[slot].stype = stype;\n  Symtable[slot].class = class;\n  Symtable[slot].size = size;\n  Symtable[slot].posn = posn;\n}\n\n// Add a global symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + class of the symbol\n// + size: number of elements, or endlabel: end label for a function\n// Return the slot number in the symbol table\nint addglob(char *name, int type, int stype, int class, int size) {\n  int slot;\n\n  // If this is already in the symbol table, return the existing slot\n  if ((slot = findglob(name)) != -1)\n    return (slot);\n\n  // Otherwise get a new slot and fill it in\n  slot = newglob();\n  updatesym(slot, name, type, stype, class, size, 0);\n  // Generate the assembly for the symbol if it's global\n  if (class == C_GLOBAL)\n    genglobsym(slot);\n  // Return the slot number\n  return (slot);\n}\n\n// Add a local symbol to the symbol table. Set up its:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements\n// Return the slot number in the symbol table, -1 if a duplicate entry\nint addlocl(char *name, int type, int stype, int class, int size) {\n  int localslot;\n\n  // If this is already in the symbol table, return an error\n  if ((localslot = findlocl(name)) != -1)\n    return (-1);\n\n  // Otherwise get a new symbol slot and a position for this local.\n  // Update the local symbol table entry.\n  localslot = newlocl();\n  updatesym(localslot, name, type, stype, class, size, 0);\n\n  // Return the local symbol's slot\n  return (localslot);\n}\n\n// Given a function's slot number, copy the global parameters\n// from its prototype to be local parameters\nvoid copyfuncparams(int slot) {\n  int i, id = slot + 1;\n\n  for (i = 0; i < Symtable[slot].nelems; i++, id++) {\n    addlocl(Symtable[id].name, Symtable[id].type, Symtable[id].stype,\n\t    Symtable[id].class, Symtable[id].size);\n  }\n}\n\n\n// Determine if the symbol s is in the symbol table.\n// Return its slot position or -1 if not found.\nint findsymbol(char *s) {\n  int slot;\n\n  slot = findlocl(s);\n  if (slot == -1)\n    slot = findglob(s);\n  return (slot);\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globs = 0;\n  Locls = NSYMBOLS - 1;\n}\n"
  },
  {
    "path": "29_Refactoring/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:15 on line 5\n"
  },
  {
    "path": "29_Refactoring/tests/err.input32.c",
    "content": "Unknown variable:cow on line 4\n"
  },
  {
    "path": "29_Refactoring/tests/err.input33.c",
    "content": "Incompatible type to return on line 4\n"
  },
  {
    "path": "29_Refactoring/tests/err.input34.c",
    "content": "For now, declaration of local arrays is not implemented on line 4\n"
  },
  {
    "path": "29_Refactoring/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 4\n"
  },
  {
    "path": "29_Refactoring/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:3 on line 4\n"
  },
  {
    "path": "29_Refactoring/tests/err.input37.c",
    "content": "Unexpected token in parameter list:15 on line 3\n"
  },
  {
    "path": "29_Refactoring/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:3 on line 4\n"
  },
  {
    "path": "29_Refactoring/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 4\n"
  },
  {
    "path": "29_Refactoring/tests/err.input40.c",
    "content": "No return for function with non-void type on line 4\n"
  },
  {
    "path": "29_Refactoring/tests/err.input41.c",
    "content": "Can't return from a void function on line 3\n"
  },
  {
    "path": "29_Refactoring/tests/err.input42.c",
    "content": "Undeclared function:fred on line 3\n"
  },
  {
    "path": "29_Refactoring/tests/err.input43.c",
    "content": "Undeclared array:b on line 3\n"
  },
  {
    "path": "29_Refactoring/tests/err.input44.c",
    "content": "Unknown variable:z on line 3\n"
  },
  {
    "path": "29_Refactoring/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "29_Refactoring/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 3\n"
  },
  {
    "path": "29_Refactoring/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "29_Refactoring/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "29_Refactoring/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 6\n"
  },
  {
    "path": "29_Refactoring/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 6\n"
  },
  {
    "path": "29_Refactoring/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 4\n"
  },
  {
    "path": "29_Refactoring/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 5\n"
  },
  {
    "path": "29_Refactoring/tests/input01.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input02.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input03.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input04.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input05.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input06.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input07.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input08.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input09.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input10.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input11.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input12.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input13.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input14.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input15.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input16.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input17.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input18.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input18a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input19.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input20.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input21.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input22.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input23.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input24.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input25.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input26.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input27.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input28.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input29.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input31.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input32.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input33.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input34.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input35.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input36.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "29_Refactoring/tests/input37.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "29_Refactoring/tests/input38.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "29_Refactoring/tests/input39.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "29_Refactoring/tests/input40.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "29_Refactoring/tests/input41.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "29_Refactoring/tests/input42.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "29_Refactoring/tests/input43.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "29_Refactoring/tests/input44.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "29_Refactoring/tests/input45.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "29_Refactoring/tests/input46.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "29_Refactoring/tests/input47.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "29_Refactoring/tests/input48.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "29_Refactoring/tests/input49.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input50.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input51.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input52.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/input55.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i ../lib/printint.c\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "29_Refactoring/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "29_Refactoring/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "29_Refactoring/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "29_Refactoring/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "29_Refactoring/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "29_Refactoring/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "29_Refactoring/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "29_Refactoring/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "29_Refactoring/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "29_Refactoring/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "29_Refactoring/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "29_Refactoring/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "29_Refactoring/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "29_Refactoring/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "29_Refactoring/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "29_Refactoring/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "29_Refactoring/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "29_Refactoring/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "29_Refactoring/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "29_Refactoring/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "29_Refactoring/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "29_Refactoring/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "29_Refactoring/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "29_Refactoring/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "29_Refactoring/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "29_Refactoring/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "29_Refactoring/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "29_Refactoring/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "29_Refactoring/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "29_Refactoring/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "29_Refactoring/tests/out.input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "29_Refactoring/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "29_Refactoring/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "29_Refactoring/tests/out.input55.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "29_Refactoring/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "29_Refactoring/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "29_Refactoring/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n  case A_IF:\n    Lfalse = gendumplabel();\n    for (int i = 0; i < level; i++)\n      fprintf(stdout, \" \");\n    fprintf(stdout, \"A_IF\");\n    if (n->right) {\n      Lend = gendumplabel();\n      fprintf(stdout, \", end L%d\", Lend);\n    }\n    fprintf(stdout, \"\\n\");\n    dumpAST(n->left, Lfalse, level + 2);\n    dumpAST(n->mid, NOLABEL, level + 2);\n    if (n->right)\n      dumpAST(n->right, NOLABEL, level + 2);\n    return;\n  case A_WHILE:\n    Lstart = gendumplabel();\n    for (int i = 0; i < level; i++)\n      fprintf(stdout, \" \");\n    fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n    Lend = gendumplabel();\n    dumpAST(n->left, Lend, level + 2);\n    dumpAST(n->right, NOLABEL, level + 2);\n    return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n  case A_GLUE:\n    fprintf(stdout, \"\\n\\n\");\n    return;\n  case A_FUNCTION:\n    fprintf(stdout, \"A_FUNCTION %s\\n\", Symtable[n->id].name);\n    return;\n  case A_ADD:\n    fprintf(stdout, \"A_ADD\\n\");\n    return;\n  case A_SUBTRACT:\n    fprintf(stdout, \"A_SUBTRACT\\n\");\n    return;\n  case A_MULTIPLY:\n    fprintf(stdout, \"A_MULTIPLY\\n\");\n    return;\n  case A_DIVIDE:\n    fprintf(stdout, \"A_DIVIDE\\n\");\n    return;\n  case A_EQ:\n    fprintf(stdout, \"A_EQ\\n\");\n    return;\n  case A_NE:\n    fprintf(stdout, \"A_NE\\n\");\n    return;\n  case A_LT:\n    fprintf(stdout, \"A_LE\\n\");\n    return;\n  case A_GT:\n    fprintf(stdout, \"A_GT\\n\");\n    return;\n  case A_LE:\n    fprintf(stdout, \"A_LE\\n\");\n    return;\n  case A_GE:\n    fprintf(stdout, \"A_GE\\n\");\n    return;\n  case A_INTLIT:\n    fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n    return;\n  case A_STRLIT:\n    fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->id);\n    return;\n  case A_IDENT:\n    if (n->rvalue)\n      fprintf(stdout, \"A_IDENT rval %s\\n\", Symtable[n->id].name);\n    else\n      fprintf(stdout, \"A_IDENT %s\\n\", Symtable[n->id].name);\n    return;\n  case A_ASSIGN:\n    fprintf(stdout, \"A_ASSIGN\\n\");\n    return;\n  case A_WIDEN:\n    fprintf(stdout, \"A_WIDEN\\n\");\n    return;\n  case A_RETURN:\n    fprintf(stdout, \"A_RETURN\\n\");\n    return;\n  case A_FUNCCALL:\n    fprintf(stdout, \"A_FUNCCALL %s\\n\", Symtable[n->id].name);\n    return;\n  case A_ADDR:\n    fprintf(stdout, \"A_ADDR %s\\n\", Symtable[n->id].name);\n    return;\n  case A_DEREF:\n    if (n->rvalue)\n      fprintf(stdout, \"A_DEREF rval\\n\");\n    else\n      fprintf(stdout, \"A_DEREF\\n\");\n    return;\n  case A_SCALE:\n    fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n    return;\n  case A_PREINC:\n    fprintf(stdout, \"A_PREINC %s\\n\", Symtable[n->id].name);\n    return;\n  case A_PREDEC:\n    fprintf(stdout, \"A_PREDEC %s\\n\", Symtable[n->id].name);\n    return;\n  case A_POSTINC:\n    fprintf(stdout, \"A_POSTINC\\n\");\n    return;\n  case A_POSTDEC:\n    fprintf(stdout, \"A_POSTDEC\\n\");\n    return;\n  case A_NEGATE:\n    fprintf(stdout, \"A_NEGATE\\n\");\n    return;\n  default:\n    fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "29_Refactoring/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return ((type & 0xf) == 0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "30_Design_Composites/Makefile",
    "content": "HSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out\n\ntest: cwj tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "30_Design_Composites/Readme.md",
    "content": "# Part 30: Designing Structs, Unions and Enums\n\nI'm going to sketch out my design ideas for implementing structs, unions and\nenums in ths part of our compiler writing journey. As with functions, it's\ngoing to take a number of following steps to get it all implemented.\n\nI've also chosen to rewrite the symbol table from being a single array to being\nseveral singly-linked lists. I already mentioned my intention to do this: my\nideas on how to implement the composite types made it important to rewrite the\nsymbol table implementation at this point.\n\nBefore we get into the code changes, let's look at what, exactly, are composite\ntypes.\n\n## Composite Types, Enums and Typedefs\n\nIn C, [structs](https://en.wikipedia.org/wiki/Struct_(C_programming_language))\nand [unions](https://en.wikipedia.org/wiki/Union_type#C/C++) are known\nas *composite types*. A struct or union variable can have many members\ncontained within. The difference is that, in a struct, the members are\nguaranteed not to overlap in memory whereas, in a union, we desire that\nall the members share the same memory locations.\n\nAn example of a struct type is:\n\n```c\nstruct foo {\n  int  a;\n  int  b;\n  char c;\n};\n\nstruct foo fred;\n```\n\nThe variable `fred` is of type `struct foo`, and it has three members `a`, `b` and\n`c`. We can now do these three assignments to `fred`:\n\n```c\n  fred.a= 4;\n  fred.b= 7;\n  fred.c= 'x';\n```\n\nand all three values are stored in the respective members in `fred`.\n\nOn the other hand, here is an example of a union type:\n\n```c\nunion bar {\n  int  a;\n  int  b;\n  char c;\n};\n\nunion bar jane;\n```\n\nIf we perform these statements:\n\n```c\n  jane.a= 5;\n  printf(\"%d\\n\", jane.b);\n```\n\nthen the value 5 will be printed as the `a` and `b` members occupy the same\nmemory location in the `jane` union.\n\n### Enums\n\nI'll talk about enums here even though they don't define a composite type like\nthe structs and unions.\nIn C, [enums](https://en.wikipedia.org/wiki/Enumerated_type#C) are essentially\na way to give names to integer values. An enum represents a list of\nnamed integer values.\n\nAs an example, we can define these new identifiers:\n\n```c\nenum { apple=1, banana, carrot, pear=10, peach, mango, papaya };\n```\n\nWe now have these named integer values:\n\n|  Name  | Value |\n|:------:|:-----:|\n| apple  |   1   |\n| banana |   2   |\n| carrot |   3   |\n| pear   |  10   |\n| peach  |  11   |\n| mango  |  12   |\n| papaya |  13   |\n\nThere are some interesting issues with enums that I didn't know, which I'll cover below.\n\n### Typedefs\n\nI should also touch on typedefs at this point, even though I won't need to\nimplement them to get our compiler to compile itself. A \n[typedef](https://en.wikipedia.org/wiki/Typedef) is a way to give an existing\ntype another name. It's often used to make naming structs and unions easier.\n\nUsing a previous example, we can write:\n\n```c\ntypedef struct foo Husk;\nHusk kim;\n```\n\n`kim` is of type `Husk` which is the same as saying that `kim` is of type `struct foo`.\n\n## Types versus Symbols?\n\nSo, if structs, unions and typedefs are new types, what have they got to do with\nthe symbol table which holds variable and function definitions? And enums are\njust names for integer literals, again not variables or functions.\n\nThe thing is, all of these things have *names*: the name of the struct or union,\nthe name of their members, the types of the members, the names of the enumerated\nvalues, and the names of the typedefs.\n\nWe need to store these names somewhere, and we need to be able to find them. For\nthe struct/union members, we need to find their underlying types. For the enumerated\nnames, we need to look up their integer literal values.\n\nThis is why I'm going to use the symbol table to store all of these things. But,\nwe need to break up the table into several specific lists, so that we can find\nparticular things and avoid finding things that we don't want to find.\n\n## Redesigning the Symbol Table Structure\n\nLet's have, to start with:\n\n + a singly-linked list for the global variables and functions\n + a singly-linked list for the variables local to the current function\n + a singly-linked list for the parameters local to the current function\n\nWith the old array-based symbol table, we had to skip over the function parameters\nwhen we were searching for global variables and functions. So, let's also have a\nlist in a separate direction for the parameters of a function:\n\n```c\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int stype;                    // Structural type for the symbol\n  ...\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First parameter of a function\n};\n```\n\nLet's have a look, graphically, how this will\nlook for the following code fragment:\n\n```c\n  int a;\n  char b;\n  void func1(int x, int y);\n  void main(int argc, char **argv) {\n    int loc1;\n    int loc2;\n  }\n```\n\nThis will be stored in three symbol table lists like this:\n\n![](Figs/newsymlists.png)\n\nNote that we have three list \"heads\" which point to the three lists.\nWe can now walk the global symbol list and not have to skip over the\nparameters, as each function keeps its parameters on its own list.\n\nWhen it comes time to parse a function's body, we can point the parameter\nlist at the function's parameter list. Then, as local variables get declared,\nthey are simply appended to the local variable list.\n\nThen, once the function's body is parsed and its assembly code generated,\nwe can set the parameter and local lists back to being empty without\ndisturbing the parameter list in the globally-visible function.\nThis is where I'm up to with the rewrite of the symbol table. But it doesn't\nshow how we can implement structs, unions and enums.\n\n## Interesting Issues and Considerations\n\nBefore we do see how to augment the existing symbol table node, plus\nsingly-linked lists, to support structs, unions and enums, we first have\nto consider some of their more interesting issues.\n\n### Unions\n\nWe'll start with unions. Firstly, we can put a union into a struct.\nSecondly, the union doesn't need a name. Thirdly, a variable does not\nneed to be declared in the struct to hold the union. As an example:\n\n```c\n#include <stdio.h>\nstruct fred {\n  int x;\n  union {\n    int a;\n    int b;\n  };            // No need to declare a variable of this union type\n};\n\nint main() {\n  struct fred foo;\n  foo.x= 5;\n  foo.a= 12;                            // a is treated like a struct member\n  foo.b= 13;                            // b is treated like a struct member\n  printf(\"%d %d\\n\", foo.x, foo.a);      // Print 5 and 13\n}\n```\n\nWe need to be able to support this. Anonymous unions (and structs) will\nbe easy: we just leave the `name` in the symbol table node set to NULL.\nBut there is no variable name for this union: I think we can implement this\nby having the struct's member name also set to NULL, i.e.\n\n![](Figs/structunion1.png)\n\n### Enums\n\nI've used enums before but I haven't really thought about implementing them\nthat much. So I wrote the following C program to see if I could \"break\" enums:\n\n```c\n#include <stdio.h>\n\nenum fred { bill, mary, dennis };\nint fred;\nint mary;\nenum fred { chocolate, spinach, glue };\nenum amy { garbage, dennis, flute, amy };\nenum fred x;\nenum { pie, piano, axe, glyph } y;\n\nint main() {\n  x= bill;\n  y= pie;\n  y= bill;\n  x= axe;\n  x= y;\n  printf(\"%d %d %ld\\n\", x, y, sizeof(x));\n}\n```\n\nThe questions are:\n\n + Can we redeclare an enum list with different elements, e.g. `enum fred` and\n   `enum fred`?\n + Can we declare a variable with the same name as an enum list, e.g. `fred`?\n + Can we declare a variable with the same name as an enum value, e.g. `mary`?\n + Can we reuse the name of an enum value from one enum list in another, e.g.\n   `dennis` and `dennis`?\n + Can we assign a value from one enum list to a variable declared to be\n   of a different enum list?\n + Can we assign bewteen variables declared to be of different enum lists?\n\nAnd here is what `gcc` produces as errors and warnings:\n\n```c\nz.c:4:5: error: ‘mary’ redeclared as different kind of symbol\n int mary;\n     ^~~~\nz.c:2:19: note: previous definition of ‘mary’ was here\n enum fred { bill, mary, dennis };\n                   ^~~~\nz.c:5:6: error: nested redefinition of ‘enum fred’\n enum fred { chocolate, spinach, glue };\n      ^~~~\nz.c:5:6: error: redeclaration of ‘enum fred’\nz.c:2:6: note: originally defined here\n enum fred { bill, mary, dennis };\n      ^~~~\nz.c:6:21: error: redeclaration of enumerator ‘dennis’\n enum amy { garbage, dennis, flute, amy };\n                     ^~~~~~\nz.c:2:25: note: previous definition of ‘dennis’ was here\n enum fred { bill, mary, dennis };\n                         ^~~~~~\n```\n\nAfter modifying and compiling the above program a few times, the answers are:\n\n + We can't redeclare `enum fred`. This seems to be the only place where\n   we need to remember the name of an enum list.\n + We can reuse the enum list identifier `fred` as a variable name.\n + We can't reuse the enum value identifier `mary` in another enum list,\n   nor as a variable name.\n + We can assign enum value anywhere: they seem to be treated simply as\n   names for literal integer values.\n + It also appears that we can replace `enum` and `enum X` as a type\n   with the word `int`.\n\n## Design Considerations\n\nOK, so I think we're at the point where we can start listing what we want:\n\n + a list of named and unnamed structs, with the names of the members in\n   each struct and the type details for each member. Also, we will need\n   the memory offset for the member from the \"base\" of the struct.\n + ditto for named and unnamed structs, although the offset will always be zero.\n + a list of enumerated list names and the actual enumeration names and their associated\n   values.\n + in the symbol table, we need the existing `type` information for non-composite\n   types, but we'll also need a pointer to the relevant composite type, if a\n   symbol is a struct or a union.\n + given that a struct can have a member which is a pointer to itself, we will\n   need to be able to point the member's type back to the same struct.\n\n## Changes to the Symbol Table Node Structure\n\nBelow, in bold, are my changes to the current singly-linked list symbol table node:\n\n<pre>\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  <b>struct symtable *ctype;       // If needed, pointer to the composite type</b>\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  union {\n    int size;                   // Number of elements in the symbol\n    int endlabel;               // For functions, the end label\n    <b>int intvalue;               // For enum symbols, the associated value</b>\n  };\n  union {\n    int nelems;                 // For functions, # of params\n    int posn;                   // For locals, the negative offset\n                                // from the stack base pointer\n  };\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n</pre>\n\nAlong with this new node structure, we will have six linked lists:\n\n + a singly-linked list for the global variables and functions\n + a singly-linked list for the variables local to the current function\n + a singly-linked list for the parameters local to the current function\n + a singly-linked list for the struct types that have been defined\n + a singly-linked list for the union types that have been defined\n + a singly-linked list for the enum names and enumerated values that have been defined\n\n## The Use Cases for the New Symbol Table Node\n\nLet's look at how each field in the above struct will get used by the six lists\nI enumerated above.\n\n### New Types\n\nWe will have two new types, P_STRUCT and P_UNION, which I'll describe below.\n\n### Global Variables and Functions, Parameter Variables, Local Variables\n\n + *name*: name of the variable or function.\n + *type*: type of the variable, or the function's return value, plus the 4-bit\n   indirection level.\n + *ctype*: if the variable is a P_STRUCT or P_UNION, this field points at the\n   associated struct or union definition in the relevant singly-linked list.\n + *stype*: structural type of the variable or function: S_VARIABLE, S_FUNCTION or\n   S_ARRAY.\n + *class*: storage class for the variable: C_GLOBAL, C_LOCAL, or C_PARAM.\n + *size*: for variables, the total size in bytes. For arrays, the number of elements\n   in the array. We will use this to implement `sizeof()` later.\n + *endlabel*: for functions, the end label which we can `return` to.\n + *nelems*: for functions, the number of parameters.\n + *posn*: for local variables and parameters, the negative offset of the variable\n   from the stack base pointer.\n + *next*: the next symbol in this list.\n + *member*: for functions, a pointer to the first parameter's node. NULL for\n    variables.\n\n### Struct Types\n\n + *name*: name of the struct type, or NULL if it is anonymous.\n + *type*: always P_STRUCT, not really required.\n + *ctype*: unused.\n + *stype*: unused.\n + *class*: unused.\n + *size*: the total size of the struct in bytes, to be used by `sizeof()` later.\n + *nelems*: the number of members in the struct.\n + *next*: the next struct type that has been defined.\n + *member*: a pointer to the first struct member's node.\n\n### Union Types\n\n + *name*: name of the union type, or NULL if it is anonymous.\n + *type*: always P_UNION, not really required.\n + *ctype*: unused.\n + *stype*: unused.\n + *class*: unused.\n + *size*: the total size of the union in bytes, to be used by `sizeof()` later.\n + *nelems*: the number of members in the union.\n + *next*: the next union type that has been defined.\n + *member*: a pointer to the first union member's node.\n\n### Struct and Union Members\n\nEach member is essentially a variable, so there is a strong similarity to normal\nvariables.\n \n + *name*: name of the member.\n + *type*: type of the variable plus the 4-bit indirection level.\n + *ctype*: if the member is a P_STRUCT or P_UNION, this field points at the\n   associated struct or union definition in the relevant singly-linked list.\n + *stype*: structural type of the member: S_VARIABLE or S_ARRAY.\n + *class*: unused.\n + *size*: for variables, the total size in bytes. For arrays, the number of elements\n   in the array. We will use this to implement `sizeof()` later.\n + *posn*: the positive offset of the member from the base of the struct/union.\n + *next*: the next member in the struct/union.\n + *member*: NULL.\n\n### Enum List Names and Values\n\nI want to store all the symbols and implicit values below:\n\n```c\n  enum fred { chocolate, spinach, glue };\n  enum amy  { garbage, dennis, flute, couch };\n```\n\nWe could just link `fred` then `amy`, and use the `member` field in `fred` for\nthe `chocolate`, `spinach`, `glue` list. Ditto the `garbage` etc. list.\n\nHowever, we really only care about the `fred` and `amy` names to prevent them\nbeing reused as enum list names. What we really care about are the actual\nenumeration names and their values.\n\nTherefore I propose a couple of \"dummy\" type values: P_ENUMLIST and P_ENUMVAL.\nWe then build just a single-dimensional list like this:\n\n```c\n     fred  -> chocolate-> spinach ->   glue  ->    amy  -> garbage -> dennis -> ...\n  P_ENUMLIST  P_ENUMVAL  P_ENUMVAL  P_ENUMVAL  P_ENUMLIST  P_ENUMVAL  P_ENUMVAL\n```\n\nThus, when we use the word `glue`, we only have to walk the one list. Otherwise,\nwe'd have to find `fred`, walk `fred`'s member list, then the same for `amy`.\nI think the one list will be easier.\n\n## What Has Been Changed Already\n\nUp at the top of this document, I mentioned that I've already\nrewritten the symbol table from being a single array to being\nseveral singly-linked lists, with these new fields in the `struct symtable` node:\n\n```c\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First parameter of a function\n```\n\nSo, let's have a quick tour of the changes. Firstly, there are no functional\nchanges whatsoever.\n\n### Three Symbol Table Lists\n\nWe now have three symbol table lists in `data.h`:\n\n```c\n// Symbol table lists\nstruct symtable *Globhead, *Globtail;   // Global variables and functions\nstruct symtable *Loclhead, *Locltail;   // Local variables\nstruct symtable *Parmhead, *Parmtail;   // Local parameters\n```\n\nand all of the functions in `sym.c` have been rewritten to use them. I have written\na generic function to append to a list:\n\n```c\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n               struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node; *tail = node;\n  } else *head = *tail = node;\n  node->next = NULL;\n}\n```\n\nThere is now a function `newsym()` which is given all the field values of a\nsymbol table node. It `malloc()`s a new node, fills it in and returns it. I\nwon't give the code here.\n\nFor each list, there is a function to build and append a node to the list. One\nexample is:\n\n```c\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, int stype, int class, int size) {\n  struct symtable *sym = newsym(name, type, stype, class, size, 0);\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n```\n\nThere is a generic function to find a symbol in a list, where the `list` pointer\nis the head of the list:\n\n```c\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\nstatic struct symtable *findsyminlist(char *s, struct symtable *list) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      return (list);\n  return (NULL);\n}\n```\n\nand there are three list-specific `findXXX()` functions.\n\nThere is a function, `findsymbol()`, that tries to find a symbol in a function's\nparameter list first, then the function's local variables, then finally global\nvariables.\n\nThere is a function, `findlocl()`, that only searches a function's parameter\nlist and local variables. We use this one when we are declaring local variables\nand need to prevent a redeclaration.\n\nFinally, there is a function, `clear_symtable()`, to reset the head and tail of\nall three lists to NULL, i.e. to clear all three lists.\n\n### The Parameter and Local Lists\n\nThe global symbol lists is only cleared once each individual source code file is\nparsed. But we need to a) set up the parameter list, and b) clear the local symbol\nlist, each time we start parsing the body of a new function.\n\nSo here is how it works. When we are parsing a parameter list in `param_declaration()`\nin `expr.c`, we call `var_declaration()` for each parameter. This creates a symbol\ntable node and appends it to the parameter list, i.e. `Parmhead` and `Parmtail`.\nWhen `param_declaration()` returns, `Parmhead` points at the parameter list.\n\nBack in `function_declaration()` which is parsing the whole function (its name,\nparameter list *and* any function body), the parameter list is copied into the\nfunction's symbol table node:\n\n```c\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n\n    // Clear out the parameter list\n    Parmhead = Parmtail = NULL;\n```\n\nWe clear the parameter list by `NULL`ing `Parmhead` and `Parmtail`, as shown.\nThis would mean that all these are no longer available to search for via the global parameter list.\n\nThe solution is to set a global variable, `Functionid`, to the function's\nsymbol table entry:\n\n```c\n  Functionid = newfuncsym;\n```\n\nSo, when we call `compound_statement()` to parse the function's body,\nwe still have the parameter list available through `Functionid->member` to\ndo things like:\n\n + prevent a local variable being declared that matches a parameter name\n + use a parameter's name as a normal local variable etc.\n\nEventually, `function_declaration()` returns the AST tree which covers the\nwhole function back to `global_declarations()` which then passes it to\n`genAST()` in `gen.c` to generate the assembly code. And when `genAST()` returns,\n`global_declarations()` calls `freeloclsyms()` to clear the local and parameter\nlists and reset `Functionid` back to `NULL`.\n\n### Other Changes of Note\n\nWell, actually a heck of a lot of code had to be rewritten due to the\nchange to several linked lists for the symbol table. I'm not going to\ngo through the whole code base. But some things you can spot easily.\nFor example, symbol nodes used to be referenced with code like `Symtable[n->id]`.\nThis is now `n->sym`.\n\nAlso, a lot of the code in `cg.c` refers to symbol names, so you now see these as\n`n->sym->name`. Similarly, the code to dump the AST trees in `tree.c` now\nhas a lot of `n->sym->name` in it.\n\n## Conclusion and What's Next\n\nThis part of our journey was part design and part reimplementation. We spent\na lot of time working out what issue we will face when implementing structs,\nunions and enums. Then we redesigned the symbol table to support these\nnew concepts. Finally, we rewrote  the symbol table into three linked lists\n(for now) in preparation for the implementation of these new concepts.\n\nIn the next part of our compiler writing journey, I'll probably implement\nthe declaration of struct types, but not actually write the code for them to\nbe used. I'll do that in the following part. With both of these done, I'll\nhopefully be able to implement unions in a third part. Then, enums in the\nfourth part. We'll see! [Next step](../31_Struct_Declarations/Readme.md)\n"
  },
  {
    "path": "30_Design_Composites/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int typesize;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  typesize = cgprimsize(node->type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space\n  for (int i = 0; i < node->size; i++) {\n    switch (typesize) {\n      case 1:\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"\\t.long\\t0\\n\");\n\tbreak;\n      case 8:\n\tfprintf(Outfile, \"\\t.quad\\t0\\n\");\n\tbreak;\n      default:\n\tfatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "30_Design_Composites/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "30_Design_Composites/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int typesize;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  typesize = cgprimsize(node->type);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space\n  // original version\n  for (int i = 0; i < node->size; i++) {\n    switch(typesize) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        fatald(\"Unknown typesize in cgglobsym: \", typesize);\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(typesize) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", node->size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", node->size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", node->size);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "30_Design_Composites/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t// Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t// Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t// Local parameters\nextern_ struct symtable *Comphead, *Comptail;\t// Composite types\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "30_Design_Composites/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// Parse the current token and return\n// a primitive type enum value. Also\n// scan in the next token\nint parse_type(void) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      break;\n    case T_INT:\n      type = P_INT;\n      break;\n    case T_LONG:\n      type = P_LONG;\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    scan(&Token);\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type.\n// class is the variable's class\n// Return the pointer to variable's entry in the symbol table\nstruct symtable *var_declaration(int type, int class) {\n  struct symtable *sym = NULL;\n\n  // See if this has already been declared\n  switch (class) {\n    case C_GLOBAL:\n      if (findglob(Text) != NULL)\n\tfatals(\"Duplicate global variable declaration\", Text);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(Text) != NULL)\n\tfatals(\"Duplicate local variable declaration\", Text);\n  }\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      switch (class) {\n\tcase C_GLOBAL:\n\t  sym =\n\t    addglob(Text, pointer_to(type), S_ARRAY, class, Token.intvalue);\n\t  break;\n\tcase C_LOCAL:\n\tcase C_PARAM:\n\t  fatal(\"For now, declaration of local arrays is not implemented\");\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    switch (class) {\n      case C_GLOBAL:\n\tsym = addglob(Text, type, S_VARIABLE, class, 1);\n\tbreak;\n      case C_LOCAL:\n\tsym = addlocl(Text, type, S_VARIABLE, class, 1);\n\tbreak;\n      case C_PARAM:\n\tsym = addparm(Text, type, S_VARIABLE, class, 1);\n\tbreak;\n    }\n  }\n  return (sym);\n}\n\n// param_declaration: <null>\n//           | variable_declaration\n//           | variable_declaration ',' param_declaration\n//\n// Parse the parameters in parentheses after the function name.\n// Add them as symbols to the symbol table and return the number\n// of parameters. If funcsym is not NULL, there is an existing function\n// prototype, and the function has this symbol table pointer.\nstatic int param_declaration(struct symtable *funcsym) {\n  int type;\n  int paramcnt = 0;\n  struct symtable *protoptr = NULL;\n\n  // If there is a prototype, get the pointer\n  // to the first prototype parameter\n  if (funcsym != NULL)\n    protoptr = funcsym->member;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n    // Get the type and identifier\n    // and add it to the symbol table\n    type = parse_type();\n    ident();\n\n    // We have an existing prototype.\n    // Check that this type matches the prototype.\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    } else {\n      // Add a new parameter to the new parameter list\n      var_declaration(type, C_PARAM);\n    }\n    paramcnt++;\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n      case T_COMMA:\n\tscan(&Token);\n\tbreak;\n      case T_RPAREN:\n\tbreak;\n      default:\n\tfatald(\"Unexpected token in parameter list\", Token.token);\n    }\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((funcsym != NULL) && (paramcnt != funcsym->nelems))\n    fatals(\"Parameter count mismatch for function\", funcsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(Text)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    newfuncsym = addglob(Text, type, S_FUNCTION, C_GLOBAL, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration(oldfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel));\n}\n\n\n// Parse one or more global declarations, either\n// variables or functions\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  int type;\n\n  while (1) {\n\n    // We have to read past the type and identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    type = parse_type();\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration\n      tree = function_declaration(type);\n\n      // Only a function prototype, no code\n      if (tree == NULL)\n\tcontinue;\n\n      // A real function, generate the assembly code for it\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, C_GLOBAL);\n      semi();\n    }\n\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n  }\n}\n"
  },
  {
    "path": "30_Design_Composites/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nvoid genreturn(int reg, int id);\n\n// cg.c\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nint cgprimsize(int type);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, int stype, int class,\n\t\t\tint size, int posn);\nstruct symtable *addglob(char *name, int type, int stype,\n\t\t\t int class, int size);\nstruct symtable *addlocl(char *name, int type, int stype,\n\t\t\t int class, int size);\nstruct symtable *addparm(char *name, int type, int stype,\n\t\t\t int class, int size);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findcomposite(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nstruct symtable *var_declaration(int type, int class);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint parse_type(void);\nint pointer_to(int type);\nint value_at(int type);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "30_Design_Composites/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM\t\t\t// Locally visible function parameter\n};\n\n// Symbol table structure\n// XXX Put some comments here\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  union {\n    int size;\t\t\t// Number of elements in the symbol\n    int endlabel;\t\t// For functions, the end label\n  };\n  union {\n    int nelems;\t\t\t// For functions, # of params\n    int posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  };\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  union {\t\t\t// the symbol in the symbol table\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "30_Design_Composites/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n      case T_COMMA:\n\tscan(&Token);\n\tbreak;\n      case T_RPAREN:\n\tbreak;\n      default:\n\tfatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n      // Post-increment: skip over the token\n    case T_INC:\n      scan(&Token);\n      n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n      break;\n\n      // Post-decrement: skip over the token\n    case T_DEC:\n      scan(&Token);\n      n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n      break;\n\n      // Just a variable reference\n    default:\n      n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n\tn = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n      break;\n\n    case T_STRLIT:\n      // For a STRLIT token, generate the assembly for it.\n      // Then make a leaf AST node for it. id is the string's label.\n      id = genglobstr(Text);\n      n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n      break;\n\n    case T_IDENT:\n      return (postfix());\n\n    case T_LPAREN:\n      // Beginning of a parenthesised expression, skip the '('.\n      // Scan in the expression and the right parenthesis\n      scan(&Token);\n      n = binexpr(0);\n      rparen();\n      return (n);\n\n    default:\n      fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n    case T_AMPER:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Ensure that it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"& operator must be followed by an identifier\");\n\n      // Now change the operator to A_ADDR and the type to\n      // a pointer to the original type\n      tree->op = A_ADDR;\n      tree->type = pointer_to(tree->type);\n      break;\n    case T_STAR:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's either another deref or an\n      // identifier\n      if (tree->op != A_IDENT && tree->op != A_DEREF)\n\tfatal(\"* operator must be followed by an identifier or *\");\n\n      // Prepend an A_DEREF operation to the tree\n      tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n      break;\n    case T_MINUS:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_NEGATE operation to the tree and\n      // make the child an rvalue. Because chars are unsigned,\n      // also widen this to int so that it's signed\n      tree->rvalue = 1;\n      tree = modify_type(tree, P_INT, 0);\n      tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n      break;\n    case T_INVERT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_INVERT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n      break;\n    case T_LOGNOT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_LOGNOT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n      break;\n    case T_INC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"++ operator must be followed by an identifier\");\n\n      // Prepend an A_PREINC operation to the tree\n      tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n      break;\n    case T_DEC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"-- operator must be followed by an identifier\");\n\n      // Prepend an A_PREDEC operation to the tree\n      tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n      break;\n    default:\n      tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "30_Design_Composites/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOLABEL, n->op);\n      genfreeregs();\n      genAST(n->right, NOLABEL, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, label));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n"
  },
  {
    "path": "30_Design_Composites/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Open up the input file\n  if ((Infile = fopen(filename, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "30_Design_Composites/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "30_Design_Composites/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "30_Design_Composites/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n\n  switch (Token.token) {\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration\n      // and skip over the semicolon\n      type = parse_type();\n      ident();\n      var_declaration(type, C_LOCAL);\n      semi();\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "30_Design_Composites/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, int stype, int class,\n\t\t\tint size, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  node->name = strdup(name);\n  node->type = type;\n  node->stype = stype;\n  node->class = class;\n  node->size = size;\n  node->posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(node);\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, int stype, int class, int size) {\n  struct symtable *sym = newsym(name, type, stype, class, size, 0);\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, int stype, int class, int size) {\n  struct symtable *sym = newsym(name, type, stype, class, size, 0);\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, int stype, int class, int size) {\n  struct symtable *sym = newsym(name, type, stype, class, size, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\nstatic struct symtable *findsyminlist(char *s, struct symtable *list) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead));\n}\n\n// Find a composite type.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findcomposite(char *s) {\n  return (findsyminlist(s, Comphead));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead = Globtail = NULL;\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Comphead = Comptail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:15 on line 5\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input32.c",
    "content": "Unknown variable:cow on line 4\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input33.c",
    "content": "Incompatible type to return on line 4\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input34.c",
    "content": "For now, declaration of local arrays is not implemented on line 4\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 4\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input37.c",
    "content": "Unexpected token in parameter list:15 on line 3\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 4\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input40.c",
    "content": "No return for function with non-void type on line 4\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input41.c",
    "content": "Can't return from a void function on line 3\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input42.c",
    "content": "Undeclared function:fred on line 3\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input43.c",
    "content": "Undeclared array:b on line 3\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input44.c",
    "content": "Unknown variable:z on line 3\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 3\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 6\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 6\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 4\n"
  },
  {
    "path": "30_Design_Composites/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 5\n"
  },
  {
    "path": "30_Design_Composites/tests/input01.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input02.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input03.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input04.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input05.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input06.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input07.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input08.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input09.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input10.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input11.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input12.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input13.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input14.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input15.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input16.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input17.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input18.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input18a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input19.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input20.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input21.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input22.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input23.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input24.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input25.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input26.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input27.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input28.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input29.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input31.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input32.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input33.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input34.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input35.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input36.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "30_Design_Composites/tests/input37.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "30_Design_Composites/tests/input38.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "30_Design_Composites/tests/input39.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "30_Design_Composites/tests/input40.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "30_Design_Composites/tests/input41.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "30_Design_Composites/tests/input42.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "30_Design_Composites/tests/input43.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "30_Design_Composites/tests/input44.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "30_Design_Composites/tests/input45.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "30_Design_Composites/tests/input46.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "30_Design_Composites/tests/input47.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "30_Design_Composites/tests/input48.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "30_Design_Composites/tests/input49.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input50.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input51.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input52.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/input55.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i ../lib/printint.c\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "30_Design_Composites/tests/out.input55.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "30_Design_Composites/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "30_Design_Composites/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "30_Design_Composites/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "30_Design_Composites/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return ((type & 0xf) == 0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = genprimsize(ltype);\n    rsize = genprimsize(rtype);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/Makefile",
    "content": "HSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out\n\ntest: cwj tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "31_Struct_Declarations/Readme.md",
    "content": "# Part 31: Implementing Structs, Part 1\n\nIn this part of our compiler writing journey, I've begun the process of\nimplementing structs into the language. Even though these are not yet\nfunctional, I've made substantial changes to the code just to get\nto the point where we can declare structs, and global variables of struct\ntype.\n\n## Symbol Table Changes\n\nAs I mentioned in the last part, we need to change the symbol table structure\nto include a pointer to a composite type node, when the symbol is of this\ntype. We also added a `next` pointer to support linked lists, and a\n`member` pointer. The `member` pointer of a function node holds the function's\nparameter list. We will use the `member` node for structs to hold the struct's\nmember fields.\n\nSo, we now have:\n\n```c\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If needed, pointer to the composite type\n  ...\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n```\n\nWe also have two new lists for symbols in `data.h`:\n\n```c\n// Symbol table lists\nstruct symtable *Globhead, *Globtail;     // Global variables and functions\nstruct symtable *Loclhead, *Locltail;     // Local variables\nstruct symtable *Parmhead, *Parmtail;     // Local parameters\nstruct symtable *Membhead, *Membtail;     // Temp list of struct/union members\nstruct symtable *Structhead, *Structtail; // List of struct types\n```\n\n## Changes to `sym.c`\n\nThroughout `sym.c`, and elsewhere in the code, we used to only receive\nthe `int type` argument to determine the type of something. This isn't\nenough now that we have composite types: the P_STRUCT integer value\ntells us that something is a struct, not which one.\n\nTherefore, many functions now receive an `int type` argument and also a\n`struct symtable *ctype` argument. When `type` is P_STRUCT, `ctype`\npoints at the node which defines this particular struct type.\n\nIn `sym.c`, all the `addXX()` functions have been modified to have this\nextra argument. There is also a new `addmemb()` function and a new\n`addstruct()` function to add nodes to these two new lists. They\nfunction identically to the other `addXX()` functions but just on a\ndifferent list. I will come back to these functions later.\n\n## A New Token\n\nWe have our first new token, P_STRUCT, in quite a while. It goes with\nthe matching `struct` keyword. I'll omit the changes to `scan.c` as\nthey are minor.\n\n## Parsing Structs in our Grammar\n\nThere are a bunch of places where we need to parse the `struct` keyword:\n\n  + the definition of a named struct\n  + the definition of an unnamed struct followed by a variable of this type\n  + the definition of a struct within another struct or union\n  + the definition of a variable of a previously defined struct type\n\nAt first, I wasn't sure where to fit in the parsing of structs. Should I\nassume that we are parsing a new struct definition, but bail out when I\nsee a variable identifier, or assume a variable declaration?\n\nIn the end, I realised that, after seeing `struct <identifier>`, I had\nto assume that this was just the naming of a type, just as `int` is the\nnaming of the `int` type. We had to parse the next token to determine\notherwise.\n\nTherefore, I modified `parse_type()` in `decl.c` to parse both scalar\ntypes (e.g. `int`) and composite types (e.g. `struct foo`). And now\nthat it can return a composite type, I had to find a way to return\nthe pointer to the node that defines this composite type:\n\n```c\n// Parse the current token and return\n// a primitive type enum value and a pointer\n// to any composite type.\n// Also scan in the next token\nint parse_type(struct symtable **ctype) {\n  int type;\n  switch (Token.token) {\n    ...         // Existing code for T_VOID, T_CHAR etc.\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = struct_declaration();\n      break;\n    ...\n```\n\nWe call `struct_declaration()`to either look up an existing struct type\nor to parse the declaration of the new struct type.\n\n## Refactoring The Parsing of a Variable List\n\nIn our old code, there was a function called `param_declaration()` that\nparsed a list of parameters separated by commas, e.g.\n\n```c\nint fred(int x, char y, long z);\n```\n\nsuch as you would find as the parameter list for a function declaration.\nWell, a struct and union declaration also has a list of variables,\nexcept that they are separated by semicolons and surrounded by curly\nbrackets, e.g.\n\n```c\nstruct fred { int x; char y; long z; };\n```\n\nIt makes sense to refactor the function to parse both lists. It now\nis passed two tokens: the separating token, e.g. T_SEMI and the ending\ntoken, e.g. T_RBRACE. Thus, we can use it to parse both styles of lists.\n\n```c\n// Parse a list of variables.\n// Add them as symbols to one of the symbol table lists, and return the\n// number of variables. If funcsym is not NULL, there is an existing function\n// prototype, so compare each variable's type against this prototype.\nstatic int var_declaration_list(struct symtable *funcsym, int class,\n                                int separate_token, int end_token) {\n    ...\n    // Get the type and identifier\n    type = parse_type(&ctype);\n    ...\n    // Add a new parameter to the right symbol table list, based on the class\n    var_declaration(type, ctype, class);\n}\n```\n\nWhen we are parsing function parameter lists, we call:\n\n```c\n    var_declaration_list(oldfuncsym, C_PARAM, T_COMMA, T_RPAREN);\n```\n\nWhen we are parsing struct member lists, we call:\n\n```c\n    var_declaration_list(NULL, C_MEMBER, T_SEMI, T_RBRACE);\n```\n\nAlso note that the call to `var_declaration()` now is given the type of\nthe variable, the composite type pointer (if it is a struct or union),\nand the variable's class. \n\nNow we can parse the lists of members of a struct. So let's see how we\nparse the whole struct.\n\n## The `struct_declaration()` Function\n\nLet's take this in stages.\n\n```c\nstatic struct symtable *struct_declaration(void) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  int offset;\n\n  // Skip the struct keyword\n  scan(&Token);\n\n  // See if there is a following struct name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    ctype = findstruct(Text);\n    scan(&Token);\n  }\n```\n\nAt this point we have seen `struct` possibly followed by an identifier.\nIf this is an existing struct type, `ctype` now points at the existing\ntype node. Otherwise, `ctype` is NULL.\n\n```c\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct type\", Text);\n    return (ctype);\n  }\n```\n\nWe didn't see a '{', so this has to be just the naming of an existing type.\n`ctype` cannot be NULL, so we check that first and then simply return the\npointer to this existing struct type. This is going to go back to\n`parse_type()` when we did:\n\n```c\n      type = P_STRUCT; *ctype = struct_declaration();\n```\n\nBut, assuming we didn't return, we must have found a '{', and this signals\nthe definition of a struct type. Let's go on...\n\n```c\n  // Ensure this struct type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct\", Text);\n\n  // Build the struct node and skip the left brace\n  ctype = addstruct(Text, P_STRUCT, NULL, 0, 0);\n  scan(&Token);\n```\n\nWe can't declare a struct with the same name twice, so prevent this.\nThen build the beginnings of the new struct type as a node in the\nsymbol table. All we have so far is its name and that it is of P_STRUCT type.\n\n```c\n  // Scan in the list of members and attach\n  // to the struct type's node\n  var_declaration_list(NULL, C_MEMBER, T_SEMI, T_RBRACE);\n  rbrace();\n```\n\nThis parses the list of members. For each one, a new symbol node is appended\nto the list that `Membhead` and `Membtail` point to. This list is only\ntemporary, because the next lines of code move the member list into the \nnew struct type node:\n\n```c\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n```\n\nWe now have a struct type node with a name, and the list of members in the\nstruct. What's left to do? Well, we now need to determine:\n\n  + the overall size of the struct, and\n  + the offset of each member from the base of the struct\n\nSome of this is very hardware-specific due to the alignment of scalar\nvalues in memory. So I'll give the code as it stands now, and then\nfollow the function call structure later.\n\n```c\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->posn = 0;\n  offset = typesize(m->type, m->ctype);\n```\n\nWe now have a new function, `typesize()` to get the size of any type:\nscalar, pointer or composite. The first member's position is set to zero,\nand we use its size to determine the first possible byte where the next\nmember could be stored. But now we need to worry about alignment.\n\nAs an example, on a 32-bit architecture where 4-byte scalar values have\nto be aligned on a 4-byte boundary:\n\n```c\nstruct {\n  char x;               // At offset 0\n  int y;                // At offset 4, not 1\n};\n```\n\nSo here is the code to calculate the offset of each successive member:\n\n```c\n  // Set the position of each successive member in the struct\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    m->posn = genalign(m->type, offset, 1);\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n```\n\nWe have a new function, `genalign()` that takes a current offset and\nthe type that we need to align, and returns the first offset that\nsuits the alignment of this type. For example, `genalign(P_INT, 3, 1)`\nmight return 4 if P_INTs have to be 4-aligned. I'll discuss the final 1\nargument soon.\n\nSo, `genalign()` works out the correct alignment for this member, and\nthen we add on this member's size to get the next free (unaligned)\nposition which is available for the next member.\n\nOnce we have done the above for all the members in the list, the\n`offset` is the size in bytes of the overall struct. So:\n\n```c\n  // Set the overall size of the struct\n  ctype->size = offset;\n  return (ctype);\n}\n```\n\n## The `typesize()` Function\n\nIt's time to follow all the new functions to see what they do and how they\ndo it. We'll start with `typesize()` in `types.c`:\n\n```c\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT)\n    return(ctype->size);\n  return(genprimsize(type));\n}\n```\n\nIf the type is a struct, return the size from the struct's type node.\nOtherwise it's a scalar or pointer type, so ask `genprimsize()`\n(which calls the hardware-specific `cgprimsize()`) to get the type's size.\nNice and easy.\n\n## The `genalign()` and `cgalign()` Functions\n\nNow we get into some not so nice code. Given a type and an existing\nunaligned offset, we need to know which is the next aligned position\nto place a value of the given type.\n\nI also was worried that we might need to do this on the stack, which\ngrows downwards not upwards. So there is a third argument to the function:\nthe *direction* in which we need to find the next aligned position.\n\nAlso, the knowledge of alignment is hardware specific, so:\n\n```c\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n```\n\nand we turn our attention to `cgalign()` in `cg.c`:\n\n```c\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch(type) {\n    case P_CHAR: return (offset);\n    case P_INT:\n    case P_LONG: break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment= 4;\n  offset = (offset + direction * (alignment-1)) & ~(alignment-1);\n  return (offset);\n}\n```\n\nFirstly, yes I know that we don't have to worry about alignment in the\nx86-64 architecture. But I thought we should go through the exercise of\ndealing with alignment, so there is an example of it being done which can\nbe borrowed for other backends that may be written.\n\nThe code returns the given offset for `char` types, as they can be\nstored at any alignment. But we enforce a 4-byte alignment on `int`s\nand `long`s.\n\nLet's break down the big offset expression. The first `alignment-1`\nturns `offset` 0 into 3, 1 into 4, 2 into 5 etc. Then, at the end\nwe AND this with the inverse of 3, i.e. ...111111100 to discard the\nlast two bits and lower the value back down to the correct alignment.\n\nThus:\n\n| Offset | Add Value | New Offset |\n|:------:|:---------:|:----------:|\n|   0    |    3      |    0       |\n|   1    |    4      |    4       |\n|   2    |    5      |    4       |\n|   3    |    6      |    4       |\n|   4    |    7      |    4       |\n|   5    |    8      |    8       |\n|   6    |    9      |    8       |\n|   7    |   10      |    8       |\n\nAn offset of 0 stays at zero, but values 1 to 3 are pushed up to 4.\n4 stays aligned at 4, but 5 to 7 get pushed up to 8.\n\nNow the magic. A `direction` of 1 does everything that we have seen so far.\nA `direction` of -1 sends the offset in the opposite direction to ensure\nthat the value's \"high end\" won't hit what's above it:\n\n| Offset | Add Value | New Offset |\n|:------:|:---------:|:----------:|\n|   0    |   -3      |   -4       |\n|  -1    |   -4      |   -4       |\n|  -2    |   -5      |   -8       |\n|  -3    |   -6      |   -8       |\n|  -4    |   -7      |   -8       |\n|  -5    |   -8      |   -8       |\n|  -6    |   -9      |   -12      |\n|  -7    |  -10      |   -12      |\n\n## Creating a Global Struct Variable\n\nSo now we can parse a struct type, and declare a global variable to this type.\nNow let's modify the code to allocate the memory space for a global variable:\n\n```c\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL) return;\n  if (node->stype == S_FUNCTION) return;\n\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  switch (size) {\n    case 1: fprintf(Outfile, \"\\t.byte\\t0\\n\"); break;\n    case 4: fprintf(Outfile, \"\\t.long\\t0\\n\"); break;\n    case 8: fprintf(Outfile, \"\\t.quad\\t0\\n\"); break;\n    default:\n      for (int i=0; i < size; i++)\n        fprintf(Outfile, \"\\t.byte\\t0\\n\");\n  }\n}\n  \n```\n\n## Trying The Changes Out\n\nWe don't have any new functionality apart from parsing structs,\nstoring new nodes in the symbol table and generating storage\nfor global struct variables.\n\nI have this test program, `z.c`:\n\n```c\nstruct fred { int x; char y; long z; };\nstruct foo { char y; long z; } var1;\nstruct { int x; };\nstruct fred var2;\n```\n\nwhich should create two global variables `var1` and `var2`. We create\ntwo named struct types, `fred` and `foo`, and one unnamed struct.\nThe third struct should cause an error (or at least a warning) because\nthere is no variable associated with the struct, so the struct itself\nis useless.\n\nI added some test code to print out the member offsets and struct sizes\nfor the above structs, and this is the result:\n\n```\nOffset for fred.x is 0\nOffset for fred.y is 4\nOffset for fred.z is 8\nSize of struct fred is 13\n\nOffset for foo.y is 0\nOffset for foo.z is 4\nSize of struct foo is 9\n\nOffset for struct.x is 0\nSize of struct struct is 4\n```\n\nFinally, when I do `./cwj -S z.c`, I get this assembly output:\n\n```\n        .globl  var1\nvar1:   .byte   0       // Nine bytes\n        ...\n\n        .globl  var2    // Thirteen bytes\nvar2:   .byte   0\n        ...\n```\n\n## Conclusion and What's Next\n\nIn this part I've had to change a lot of the existing code from dealing\nwith just an `int type` to dealing with an `int type; struct symtable *ctype`\npair. I'm sure I'll have to do this in more places.\n\nWe've added the parsing of struct definitions and also declarations of\nstruct variables, and we can generate the space for global struct variables.\nAt the moment, we can't use the struct variables that we have created.\nBut it's a good start. I also haven't even tried to deal with local\nstruct variables, because that involves the stack and I'm sure that\nwill be complicated.\n\nIn the next part of our compiler writing journey, I will try to \nadd the code to parse the '.' token so that we can access members\nin a struct variable. [Next step](../32_Struct_Access_pt1/Readme.md)\n"
  },
  {
    "path": "31_Struct_Declarations/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch(type) {\n    case P_CHAR: return (offset);\n    case P_INT:\n    case P_LONG: break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment= 4;\n  offset = (offset + direction * (alignment-1)) & ~(alignment-1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      for (int i=0; i < size; i++)\n        fprintf(Outfile, \"\\t.byte\\t0\\n\");\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch(type) {\n    case P_CHAR: return (offset);\n    case P_INT:\n    case P_LONG: break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment= 4;\n  offset = (offset + direction * (alignment-1)) & ~(alignment-1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  // original version\n  for (int i = 0; i < node->size; i++) {\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(size) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", node->size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", node->size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", node->size);\n      break;\n    default:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "31_Struct_Declarations/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *struct_declaration(void);\n\n\n// Parse the current token and return\n// a primitive type enum value and a pointer\n// to any composite type.\n// Also scan in the next token\nint parse_type(struct symtable **ctype) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = struct_declaration();\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type.\n// class is the variable's class\n// Return the pointer to variable's entry in the symbol table\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class) {\n  struct symtable *sym = NULL;\n\n  // See if this has already been declared\n  switch (class) {\n    case C_GLOBAL:\n      if (findglob(Text) != NULL)\n\tfatals(\"Duplicate global variable declaration\", Text);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(Text) != NULL)\n\tfatals(\"Duplicate local variable declaration\", Text);\n    case C_MEMBER:\n      if (findmember(Text) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", Text);\n  }\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      switch (class) {\n\tcase C_GLOBAL:\n\t  sym =\n\t    addglob(Text, pointer_to(type), ctype, S_ARRAY, Token.intvalue);\n\t  break;\n\tcase C_LOCAL:\n\tcase C_PARAM:\n\tcase C_MEMBER:\n\t  fatal\n\t    (\"For now, declaration of non-global arrays is not implemented\");\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    switch (class) {\n      case C_GLOBAL:\n\tsym = addglob(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_LOCAL:\n\tsym = addlocl(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_PARAM:\n\tsym = addparm(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_MEMBER:\n\tsym = addmemb(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n    }\n  }\n  return (sym);\n}\n\n// var_declaration_list: <null>\n//           | variable_declaration\n//           | variable_declaration separate_token var_declaration_list ;\n//\n// When called to parse function parameters, separate_token is ','.\n// When called to parse members of a struct/union, separate_token is ';'.\n//\n// Parse a list of variables.\n// Add them as symbols to one of the symbol table lists, and return the\n// number of variables. If funcsym is not NULL, there is an existing function\n// prototype, so compare each variable's type against this prototype.\nstatic int var_declaration_list(struct symtable *funcsym, int class,\n\t\t\t\tint separate_token, int end_token) {\n  int type;\n  int paramcnt = 0;\n  struct symtable *protoptr = NULL;\n  struct symtable *ctype;\n\n  // If there is a prototype, get the pointer\n  // to the first prototype parameter\n  if (funcsym != NULL)\n    protoptr = funcsym->member;\n\n  // Loop until the final end token\n  while (Token.token != end_token) {\n    // Get the type and identifier\n    type = parse_type(&ctype);\n    ident();\n\n    // Check that this type matches the prototype if there is one\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    } else {\n      // Add a new parameter to the right symbol table list, based on the class\n      var_declaration(type, ctype, class);\n    }\n    paramcnt++;\n\n    // Must have a separate_token or ')' at this point\n    if ((Token.token != separate_token) && (Token.token != end_token))\n      fatald(\"Unexpected token in parameter list\", Token.token);\n    if (Token.token == separate_token)\n      scan(&Token);\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((funcsym != NULL) && (paramcnt != funcsym->nelems))\n    fatals(\"Parameter count mismatch for function\", funcsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(Text)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym = addglob(Text, type, NULL, S_FUNCTION, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = var_declaration_list(oldfuncsym, C_PARAM, T_COMMA, T_RPAREN);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel));\n}\n\n// Parse struct declarations. Either find an existing\n// struct declaration, or build a struct symbol table\n// entry and return its pointer.\nstatic struct symtable *struct_declaration(void) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  int offset;\n\n  // Skip the struct keyword\n  scan(&Token);\n\n  // See if there is a following struct name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    ctype = findstruct(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct\", Text);\n\n  // Build the struct node and skip the left brace\n  ctype = addstruct(Text, P_STRUCT, NULL, 0, 0);\n  scan(&Token);\n\n  // Scan in the list of members and attach\n  // to the struct type's node\n  var_declaration_list(NULL, C_MEMBER, T_SEMI, T_RBRACE);\n  rbrace();\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the struct\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    m->posn = genalign(m->type, offset, 1);\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the struct\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  struct symtable *ctype;\n  int type;\n\n  while (1) {\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n\n    // Get the type\n    type = parse_type(&ctype);\n\n    // We might have just parsed a struct declaration\n    // with no associated variable. The next token\n    // might be a ';'. Loop back if it is. XXX. I'm\n    // not happy with this as it allows \"struct fred;\"\n    // as an accepted statement\n    if (type == P_STRUCT && Token.token == T_SEMI) {\n      scan(&Token);\n      continue;\n    }\n    // We have to read past the identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration\n      tree = function_declaration(type);\n\n      // Only a function prototype, no code\n      if (tree == NULL)\n\tcontinue;\n\n      // A real function, generate the assembly code for it\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, ctype, C_GLOBAL);\n      semi();\n    }\n  }\n}\n"
  },
  {
    "path": "31_Struct_Declarations/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint size, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint parse_type(struct symtable **ctype);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "31_Struct_Declarations/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN, T_STRUCT,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_STRUCT,\t\t\t// A struct\n  C_MEMBER\t\t\t// Member of a struct or union\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  union {\n    int size;\t\t\t// Number of elements in the symbol\n    int endlabel;\t\t// For functions, the end label\n  };\n  union {\n    int nelems;\t\t\t// For functions, # of params\n    int posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  };\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  union {\t\t\t// the symbol in the symbol table\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "31_Struct_Declarations/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n      case T_COMMA:\n\tscan(&Token);\n\tbreak;\n      case T_RPAREN:\n\tbreak;\n      default:\n\tfatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n      // Post-increment: skip over the token\n    case T_INC:\n      scan(&Token);\n      n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n      break;\n\n      // Post-decrement: skip over the token\n    case T_DEC:\n      scan(&Token);\n      n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n      break;\n\n      // Just a variable reference\n    default:\n      n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n\tn = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n      break;\n\n    case T_STRLIT:\n      // For a STRLIT token, generate the assembly for it.\n      // Then make a leaf AST node for it. id is the string's label.\n      id = genglobstr(Text);\n      n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n      break;\n\n    case T_IDENT:\n      return (postfix());\n\n    case T_LPAREN:\n      // Beginning of a parenthesised expression, skip the '('.\n      // Scan in the expression and the right parenthesis\n      scan(&Token);\n      n = binexpr(0);\n      rparen();\n      return (n);\n\n    default:\n      fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n    case T_AMPER:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Ensure that it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"& operator must be followed by an identifier\");\n\n      // Now change the operator to A_ADDR and the type to\n      // a pointer to the original type\n      tree->op = A_ADDR;\n      tree->type = pointer_to(tree->type);\n      break;\n    case T_STAR:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's either another deref or an\n      // identifier\n      if (tree->op != A_IDENT && tree->op != A_DEREF)\n\tfatal(\"* operator must be followed by an identifier or *\");\n\n      // Prepend an A_DEREF operation to the tree\n      tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n      break;\n    case T_MINUS:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_NEGATE operation to the tree and\n      // make the child an rvalue. Because chars are unsigned,\n      // also widen this to int so that it's signed\n      tree->rvalue = 1;\n      tree = modify_type(tree, P_INT, 0);\n      tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n      break;\n    case T_INVERT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_INVERT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n      break;\n    case T_LOGNOT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // Prepend a A_LOGNOT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n      break;\n    case T_INC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"++ operator must be followed by an identifier\");\n\n      // Prepend an A_PREINC operation to the tree\n      tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n      break;\n    case T_DEC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix();\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"-- operator must be followed by an identifier\");\n\n      // Prepend an A_PREDEC operation to the tree\n      tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n      break;\n    default:\n      tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOLABEL, n->op);\n      genfreeregs();\n      genAST(n->right, NOLABEL, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, label));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "31_Struct_Declarations/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Open up the input file\n  if ((Infile = fopen(filename, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration\n      // and skip over the semicolon\n      type = parse_type(&ctype);\n      ident();\n      var_declaration(type, ctype, C_LOCAL);\n      semi();\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "31_Struct_Declarations/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int size, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->size = size;\n  node->posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(node);\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_GLOBAL, size, 0);\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, size, 0);\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, size, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, size, 0);\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_STRUCT, size, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\nstatic struct symtable *findsyminlist(char *s, struct symtable *list) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:15 on line 5\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input32.c",
    "content": "Unknown variable:cow on line 4\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input33.c",
    "content": "Incompatible type to return on line 4\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input34.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 4\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input37.c",
    "content": "Unexpected token in parameter list:15 on line 3\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 4\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input40.c",
    "content": "No return for function with non-void type on line 4\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input41.c",
    "content": "Can't return from a void function on line 3\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input42.c",
    "content": "Undeclared function:fred on line 3\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input43.c",
    "content": "Undeclared array:b on line 3\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input44.c",
    "content": "Unknown variable:z on line 3\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 3\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 6\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 6\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 4\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 5\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input56.c",
    "content": "unknown struct type:var1 on line 2\n"
  },
  {
    "path": "31_Struct_Declarations/tests/err.input57.c",
    "content": "previously defined struct:fred on line 2\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input01.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input02.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input03.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input04.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input05.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input06.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input07.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input08.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input09.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input10.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input11.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input12.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input13.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input14.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input15.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input16.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input17.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input18.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input18a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input19.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input20.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input21.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input22.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input23.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input24.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input25.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input26.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input27.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input28.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input29.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input31.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input32.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input33.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input34.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input35.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input36.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input37.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input38.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input39.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input40.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input41.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input42.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input43.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input44.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input45.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input46.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input47.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input48.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input49.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input50.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input51.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input52.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input55.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input56.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "31_Struct_Declarations/tests/input57.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "31_Struct_Declarations/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i ../lib/printint.c\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "31_Struct_Declarations/tests/out.input55.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "31_Struct_Declarations/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "31_Struct_Declarations/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "31_Struct_Declarations/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "31_Struct_Declarations/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return ((type & 0xf) == 0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT)\n    return(ctype->size);\n  return(genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL); // XXX Fix soon\n    rsize = typesize(rtype, NULL); // XXX Fix soon\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/Makefile",
    "content": "HSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out\n\ntest: cwj tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "32_Struct_Access_pt1/Readme.md",
    "content": "# Part 32: Accessing Members in a Struct\n\nThis part of our compiler writing journey turned out to be quite simple. I've added\nthe '.' and '->' tokens to our language, and I've implemented one level of member\naccess to global struct variables.\n\nI'll give our test program, `tests/input58.c`, here so that you can see the\nlanguage features that I've implemented:\n\n```c\nint printf(char *fmt);\n\nstruct fred {                   // Struct declaration, done last time\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;               // Variable declaration, done last time\nstruct fred *varptr;            // Pointer variable declaration, done last time\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);         // Member access as lvalue, new\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;             // Member access as rvalue, new\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;                                // Old behaviour\n  result= varptr->x + varptr->y + varptr->z;    // Member access through pointer, new\n  printf(\"%d\\n\", result);\n  return(0);\n}\n```\n\n## The New Tokens\n\nWe have two new tokens, T_DOT and T_ARROW, to match the '.' and '->' elements\nin the input. As always, I won't give the code in `scan.c` to identify these.\n\n## Parsing the Member References\n\nThis turned out to be very similar to our existing array element accessing code.\nLet's look at the similarities and the differences. With this code:\n\n```c\n  int x[5];\n  int y;\n  ...\n  y= x[3];\n```\n\nwe get the base address of the `x` array, multiply 3 by the size of the `int` type\nin bytes (e.g.3*4 is 12), add that to the base address, and treat this as the\naddress of the `int` that we want to access. Then we dereference this address to\nget the value at that array position.\n\nAccessing a struct member is similar:\n\n```c\n  struct fred { int x; char y; long z; };\n  struct fred var2;\n  char y;\n  ...\n  y= var2.y;\n```\n\nWe get the base address of `var2`. We get the offset of the `y` member in the\n`fred` struct, add this to the the base address, and treat this as the\naddress of the `char` that we want to access. Then we dereference this address to\nget the value there.\n\n## Postfix Operators\n\nT_DOT and T_ARROW are postfix operators, like the '[' of an array reference, as they\ncome after an identifier's name. So it makes sense to add their parsing in the\nexisting `postfix()` function in `expr.c`:\n\n```c\nstatic struct ASTnode *postfix(void) {\n  ...\n    // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n  ...\n}\n```\n\nThe argument to the new `member_access()` function in `expr.c` indicates if we\nare accessing a member through a pointer or directly. Now let's look at the new\n`member_access()` in stages.\n\n```c\n// Parse the member reference of a struct (or union, soon)\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a struct (or a union, later),\n  // or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT)\n    fatals(\"Undeclared variable\", Text);\n```\n\nFirst, some error checking. I know I will have to add checking for unions here, so\nI'm not going to refactor the code just yet.\n\n```c\n  // If a pointer to a struct, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(P_STRUCT), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n```\n\nAt this point we need to get the base address of the composite variable. If we are\ngiven a pointer, we simply load the pointer's value by making an A_IDENT AST node.\nOtherwise, the identifier *is* the struct or union, so we had better get its address\nwith an A_ADDR AST node.\n\nThis node can't be an lvalue, i.e. we can't say `var2. = 5`. It has to be an rvalue.\n\n```c\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n```\n\nWe get a pointer to the composite type so that we can walk the list of members in the\ntype, and we get the member's name after the '.' or '->'\n(and confirm that it is an identifier).\n\n```c\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n```\n\nWe walk the member's list to find the matching member's name.\n\n```c\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->posn);\n\n  // Add the member's offset to the base of the struct and\n  // dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n```\n\nThe member's offset in bytes is stored in `m->posn` so we make an A_INTLIT node\nwith this value, and A_ADD it to the base address stored in `left`. At this\npoint we have an address of the member, so we dereference it (A_DEREF) to get access\nto the member's value. At this point, this is still an lvalue; this allows us to do\nboth `5 + var2.x` and `var2.x= 6`.\n\n### Running Our Test Code\n\nThe output of `tests/input58.c` is, unsurprisingly:\n\n```\n12\n99\n4005\n4116\n4116\n```\n\nLet's have a look at some of the assembly output:\n\n```\n                                        # var2.y= 'c';\n        movq    $99, %r10               # Load 'c' into %r10\n        leaq    var2(%rip), %r11        # Get base address of var2 into %r11\n        movq    $4, %r12                \n        addq    %r11, %r12              # Add 4 to this base address\n        movb    %r10b, (%r12)           # Write 'c' into this new address\n\n                                        # printf(\"%d\\n\", var2.z);\n        leaq    var2(%rip), %r10        # Get base address of var2 into %r11\n        movq    $4, %r11\n        addq    %r10, %r11              # Add 4 to this base address\n        movzbq  (%r11), %r11            # Load byte value from this address into %r11\n        movq    %r11, %rsi              # Copy it into %rsi\n        leaq    L4(%rip), %r10\n        movq    %r10, %rdi\n        call    printf@PLT              # and call printf()\n```\n\n## Conclusion and What's Next\n\nWell, this was a nice pleasant surprise to get structs to work this easily!\nI'm sure the future parts of our journey will make up for it. I also know that\nour compiler as it stands still is pretty limited. For example, it can't do this:\n\n```c\nstruct foo {\n  int x;\n  struct foo *next;\n};\n\nstruct foo *listhead;\nstruct foo *l;\n\nint main() {\n  ...\n  l= listhead->next->next;\n```\n\nas this requires following two pointer levels. The existing code can only follow\none pointer level. We will have to fix this later.\n\nIt is probably also a good time to indicate that we will have to spend a lot\nof time getting the compiler to \"do it right\". I've been adding functionality,\nbut only enough to get one specific feature to work. At some point these specific\nfeatures will have to be made more general. So there will be a \"mop up\" stage \nin this journey.\n\nNow that we have structs mostly working, in the next part of our compiler writing\njourney, I will try to add unions. [Next step](../33_Unions/Readme.md)\n"
  },
  {
    "path": "32_Struct_Access_pt1/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch(type) {\n    case P_CHAR: return (offset);\n    case P_INT:\n    case P_LONG: break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment= 4;\n  offset = (offset + direction * (alignment-1)) & ~(alignment-1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      for (int i=0; i < size; i++)\n        fprintf(Outfile, \"\\t.byte\\t0\\n\");\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch(type) {\n    case P_CHAR: return (offset);\n    case P_INT:\n    case P_LONG: break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment= 4;\n  offset = (offset + direction * (alignment-1)) & ~(alignment-1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  // original version\n  for (int i = 0; i < node->size; i++) {\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(size) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", node->size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", node->size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", node->size);\n      break;\n    default:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "32_Struct_Access_pt1/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *struct_declaration(void);\n\n\n// Parse the current token and return\n// a primitive type enum value and a pointer\n// to any composite type.\n// Also scan in the next token\nint parse_type(struct symtable **ctype) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = struct_declaration();\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type.\n// class is the variable's class\n// Return the pointer to variable's entry in the symbol table\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class) {\n  struct symtable *sym = NULL;\n\n  // See if this has already been declared\n  switch (class) {\n    case C_GLOBAL:\n      if (findglob(Text) != NULL)\n\tfatals(\"Duplicate global variable declaration\", Text);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(Text) != NULL)\n\tfatals(\"Duplicate local variable declaration\", Text);\n    case C_MEMBER:\n      if (findmember(Text) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", Text);\n  }\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      switch (class) {\n\tcase C_GLOBAL:\n\t  sym =\n\t    addglob(Text, pointer_to(type), ctype, S_ARRAY, Token.intvalue);\n\t  break;\n\tcase C_LOCAL:\n\tcase C_PARAM:\n\tcase C_MEMBER:\n\t  fatal\n\t    (\"For now, declaration of non-global arrays is not implemented\");\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    switch (class) {\n      case C_GLOBAL:\n\tsym = addglob(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_LOCAL:\n\tsym = addlocl(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_PARAM:\n\tsym = addparm(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_MEMBER:\n\tsym = addmemb(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n    }\n  }\n  return (sym);\n}\n\n// var_declaration_list: <null>\n//           | variable_declaration\n//           | variable_declaration separate_token var_declaration_list ;\n//\n// When called to parse function parameters, separate_token is ','.\n// When called to parse members of a struct/union, separate_token is ';'.\n//\n// Parse a list of variables.\n// Add them as symbols to one of the symbol table lists, and return the\n// number of variables. If funcsym is not NULL, there is an existing function\n// prototype, so compare each variable's type against this prototype.\nstatic int var_declaration_list(struct symtable *funcsym, int class,\n\t\t\t\tint separate_token, int end_token) {\n  int type;\n  int paramcnt = 0;\n  struct symtable *protoptr = NULL;\n  struct symtable *ctype;\n\n  // If there is a prototype, get the pointer\n  // to the first prototype parameter\n  if (funcsym != NULL)\n    protoptr = funcsym->member;\n\n  // Loop until the final end token\n  while (Token.token != end_token) {\n    // Get the type and identifier\n    type = parse_type(&ctype);\n    ident();\n\n    // Check that this type matches the prototype if there is one\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    } else {\n      // Add a new parameter to the right symbol table list, based on the class\n      var_declaration(type, ctype, class);\n    }\n    paramcnt++;\n\n    // Must have a separate_token or ')' at this point\n    if ((Token.token != separate_token) && (Token.token != end_token))\n      fatald(\"Unexpected token in parameter list\", Token.token);\n    if (Token.token == separate_token)\n      scan(&Token);\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((funcsym != NULL) && (paramcnt != funcsym->nelems))\n    fatals(\"Parameter count mismatch for function\", funcsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(Text)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym = addglob(Text, type, NULL, S_FUNCTION, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = var_declaration_list(oldfuncsym, C_PARAM, T_COMMA, T_RPAREN);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel));\n}\n\n// Parse struct declarations. Either find an existing\n// struct declaration, or build a struct symbol table\n// entry and return its pointer.\nstatic struct symtable *struct_declaration(void) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  int offset;\n\n  // Skip the struct keyword\n  scan(&Token);\n\n  // See if there is a following struct name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    ctype = findstruct(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct\", Text);\n\n  // Build the struct node and skip the left brace\n  ctype = addstruct(Text, P_STRUCT, NULL, 0, 0);\n  scan(&Token);\n\n  // Scan in the list of members and attach\n  // to the struct type's node\n  var_declaration_list(NULL, C_MEMBER, T_SEMI, T_RBRACE);\n  rbrace();\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the struct\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    m->posn = genalign(m->type, offset, 1);\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the struct\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  struct symtable *ctype;\n  int type;\n\n  while (1) {\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n\n    // Get the type\n    type = parse_type(&ctype);\n\n    // We might have just parsed a struct declaration\n    // with no associated variable. The next token\n    // might be a ';'. Loop back if it is. XXX. I'm\n    // not happy with this as it allows \"struct fred;\"\n    // as an accepted statement\n    if (type == P_STRUCT && Token.token == T_SEMI) {\n      scan(&Token);\n      continue;\n    }\n    // We have to read past the identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration\n      tree = function_declaration(type);\n\n      // Only a function prototype, no code\n      if (tree == NULL)\n\tcontinue;\n\n      // A real function, generate the assembly code for it\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, ctype, C_GLOBAL);\n      semi();\n    }\n  }\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint size, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint parse_type(struct symtable **ctype);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "32_Struct_Access_pt1/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN, T_STRUCT,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_STRUCT,\t\t\t// A struct\n  C_MEMBER\t\t\t// Member of a struct or union\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  union {\n    int size;\t\t\t// Number of elements in the symbol\n    int endlabel;\t\t// For functions, the end label\n  };\n  union {\n    int nelems;\t\t\t// For functions, # of params\n    int posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  };\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  union {\t\t\t// the symbol in the symbol table\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "32_Struct_Access_pt1/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct (or union, soon)\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a struct (or a union, later),\n  // or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(P_STRUCT), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->posn);\n\n  // Add the member's offset to the base of the struct and\n  // dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOLABEL, n->op);\n      genfreeregs();\n      genAST(n->right, NOLABEL, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, label));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Open up the input file\n  if ((Infile = fopen(filename, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n        t->token = T_ARROW;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration\n      // and skip over the semicolon\n      type = parse_type(&ctype);\n      ident();\n      var_declaration(type, ctype, C_LOCAL);\n      semi();\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int size, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->size = size;\n  node->posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(node);\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_GLOBAL, size, 0);\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, size, 0);\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, size, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, size, 0);\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_STRUCT, size, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\nstatic struct symtable *findsyminlist(char *s, struct symtable *list) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:15 on line 5\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input32.c",
    "content": "Unknown variable:cow on line 4\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input33.c",
    "content": "Incompatible type to return on line 4\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input34.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 4\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input37.c",
    "content": "Unexpected token in parameter list:15 on line 3\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 4\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input40.c",
    "content": "No return for function with non-void type on line 4\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input41.c",
    "content": "Can't return from a void function on line 3\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input42.c",
    "content": "Undeclared function:fred on line 3\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input43.c",
    "content": "Undeclared array:b on line 3\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input44.c",
    "content": "Unknown variable:z on line 3\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 3\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 6\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 6\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 4\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 5\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input56.c",
    "content": "unknown struct type:var1 on line 2\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input57.c",
    "content": "previously defined struct:fred on line 2\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input59.c",
    "content": "Undeclared variable:y on line 3\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input60.c",
    "content": "Undeclared variable:x on line 3\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/err.input61.c",
    "content": "Undeclared variable:x on line 3\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input01.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input02.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input03.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input04.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input05.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input06.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input07.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input08.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input09.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input10.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input11.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input12.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input13.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input14.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input15.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input16.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input17.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input18.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input18a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input19.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input20.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input21.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input22.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input23.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input24.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input25.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input26.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input27.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input28.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input29.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input31.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input32.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input33.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input34.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input35.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input36.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input37.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input38.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input39.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input40.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input41.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input42.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input43.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input44.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input45.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input46.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input47.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input48.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input49.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input50.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input51.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input52.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input55.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input56.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input57.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input58.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input59.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input60.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/input61.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i ../lib/printint.c\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input55.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/out.input58.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "32_Struct_Access_pt1/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "32_Struct_Access_pt1/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "32_Struct_Access_pt1/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return ((type & 0xf) == 0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT)\n    return(ctype->size);\n  return(genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL); // XXX Fix soon\n    rsize = typesize(rtype, NULL); // XXX Fix soon\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "33_Unions/Makefile",
    "content": "HSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out\n\ntest: cwj tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "33_Unions/Readme.md",
    "content": "# Part 33: Implementing Unions and Member Access\n\nUnions also turned out to be easy to implement for one reason: they are like\nstructs except that all members of a union are located at offset zero from the base of\nthe union. Also, the grammar of a union declaration is the same as a struct except\nfor the \"union\" keyword.\n\nThis means that we can re-use and modify the existing structs code to deal with unions.\n\n## A New Keyword: \"union\"\n\nI've added the \"union\" keyword and the T_UNION token to the scanner in `scan.c`.\nAs always, I'll omit the code that does the scanning.\n\n## The Union Symbol List\n\nAs with structs, there is a singly-linked list to store unions (in `data.h`):\n\n```c\nextern_ struct symtable *Unionhead, *Uniontail;   // List of struct types\n```\n\nIn `sym.c`, I've also written `addunion()` and `findunion()` functions to\nadd a new union type node to the list and to search for a union type with a given\nname on the list.\n\n> I'm considering merging the struct and union lists into a single composite type\n  list, but I haven't done it yet. I'll probably do it when I get around to some\n  more refactoring.\n\n## Parsing Union Declarations\n\nWe are going to modify the existing struct parsing code in `decl.c` to parse\nboth structs and unions. I'll only give the changes to the functions, not the\nwhole functions.\n\nIn `parse_type()`, we now scan the T_UNION token and call the function to parse\nboth struct and union types:\n\n```c\n  case T_STRUCT:\n    type = P_STRUCT;\n    *ctype = composite_declaration(P_STRUCT);\n    break;\n  case T_UNION:\n    type = P_UNION;\n    *ctype = composite_declaration(P_UNION);\n    break;\n```\n\nThis function `composite_declaration()` was called `struct_declaration()` in the\nlast part of our journey. It now takes the type that we are parsing.\n\n## The `composite_declaration()` Function\n\nHere are the changes:\n\n```c\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  ...\n  // Find any matching composite type\n  if (type == P_STRUCT)\n    ctype = findstruct(Text);\n  else\n    ctype = findunion(Text);\n  ...\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text, P_STRUCT, NULL, 0, 0);\n  else\n    ctype = addunion(Text, P_UNION, NULL, 0, 0);\n  ...\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->posn = genalign(m->type, offset, 1);\n    else\n      m->posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n  ...\n  return (ctype);\n}\n```\n\nThat's it. We simply change the symbol table list we are working on, and\nalways set the member offset to zero for unions. This is why I think it\nwould be worth merging the struct and union type lists into a single list.\n\n## Parsing Union Expressions\n\nAs with the union declarations, we can reuse the code that deals with\nstructs in expressions. In fact, there are very few changes to make in `expr.c`.\n\n```c\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  ...\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n```\n\nAgain, that's it. The rest of the code was generic enough that we can use it for\nunions unmodified. And I think there was only one other major change, which was\nto a function in `types.c`:\n\n```c\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n```\n\n## Testing the Union Code\n\nHere's our test program, `test/input62.c`:\n\n```c\nint printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n```\n\nThis tests that all four members in the union are at the same location, so that\na change to one member is seen as the same change to all members. We also check\nthat pointer access into a union also works.\n\n## Conclusion and What's Next\n\nThis was another nice and easy part of our compiler writing journey.\nIn the next part of our compiler writing journey, we will add enums. [Next step](../34_Enums_and_Typedefs/Readme.md)\n"
  },
  {
    "path": "33_Unions/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch(type) {\n    case P_CHAR: return (offset);\n    case P_INT:\n    case P_LONG: break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment= 4;\n  offset = (offset + direction * (alignment-1)) & ~(alignment-1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      for (int i=0; i < size; i++)\n        fprintf(Outfile, \"\\t.byte\\t0\\n\");\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "33_Unions/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "33_Unions/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch(type) {\n    case P_CHAR: return (offset);\n    case P_INT:\n    case P_LONG: break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment= 4;\n  offset = (offset + direction * (alignment-1)) & ~(alignment-1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  // original version\n  for (int i = 0; i < node->size; i++) {\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(size) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", node->size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", node->size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", node->size);\n      break;\n    default:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "33_Unions/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of struct types\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "33_Unions/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\n\n\n// Parse the current token and return\n// a primitive type enum value and a pointer\n// to any composite type.\n// Also scan in the next token\nint parse_type(struct symtable **ctype) {\n  int type;\n  switch (Token.token) {\n  case T_VOID:\n    type = P_VOID;\n    scan(&Token);\n    break;\n  case T_CHAR:\n    type = P_CHAR;\n    scan(&Token);\n    break;\n  case T_INT:\n    type = P_INT;\n    scan(&Token);\n    break;\n  case T_LONG:\n    type = P_LONG;\n    scan(&Token);\n    break;\n  case T_STRUCT:\n    type = P_STRUCT;\n    *ctype = composite_declaration(P_STRUCT);\n    break;\n  case T_UNION:\n    type = P_UNION;\n    *ctype = composite_declaration(P_UNION);\n    break;\n  default:\n    fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type.\n// class is the variable's class\n// Return the pointer to variable's entry in the symbol table\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class) {\n  struct symtable *sym = NULL;\n\n  // See if this has already been declared\n  switch (class) {\n  case C_GLOBAL:\n    if (findglob(Text) != NULL)\n      fatals(\"Duplicate global variable declaration\", Text);\n  case C_LOCAL:\n  case C_PARAM:\n    if (findlocl(Text) != NULL)\n      fatals(\"Duplicate local variable declaration\", Text);\n  case C_MEMBER:\n    if (findmember(Text) != NULL)\n      fatals(\"Duplicate struct/union member declaration\", Text);\n  }\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      switch (class) {\n      case C_GLOBAL:\n\tsym = addglob(Text, pointer_to(type), ctype, S_ARRAY, Token.intvalue);\n\tbreak;\n      case C_LOCAL:\n      case C_PARAM:\n      case C_MEMBER:\n\tfatal(\"For now, declaration of non-global arrays is not implemented\");\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    switch (class) {\n    case C_GLOBAL:\n      sym = addglob(Text, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_LOCAL:\n      sym = addlocl(Text, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym = addparm(Text, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_MEMBER:\n      sym = addmemb(Text, type, ctype, S_VARIABLE, 1);\n      break;\n    }\n  }\n  return (sym);\n}\n\n// var_declaration_list: <null>\n//           | variable_declaration\n//           | variable_declaration separate_token var_declaration_list ;\n//\n// When called to parse function parameters, separate_token is ','.\n// When called to parse members of a struct/union, separate_token is ';'.\n//\n// Parse a list of variables.\n// Add them as symbols to one of the symbol table lists, and return the\n// number of variables. If funcsym is not NULL, there is an existing function\n// prototype, so compare each variable's type against this prototype.\nstatic int var_declaration_list(struct symtable *funcsym, int class,\n\t\t\t\tint separate_token, int end_token) {\n  int type;\n  int paramcnt = 0;\n  struct symtable *protoptr = NULL;\n  struct symtable *ctype;\n\n  // If there is a prototype, get the pointer\n  // to the first prototype parameter\n  if (funcsym != NULL)\n    protoptr = funcsym->member;\n\n  // Loop until the final end token\n  while (Token.token != end_token) {\n    // Get the type and identifier\n    type = parse_type(&ctype);\n    ident();\n\n    // Check that this type matches the prototype if there is one\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    } else {\n      // Add a new parameter to the right symbol table list, based on the class\n      var_declaration(type, ctype, class);\n    }\n    paramcnt++;\n\n    // Must have a separate_token or ')' at this point\n    if ((Token.token != separate_token) && (Token.token != end_token))\n      fatald(\"Unexpected token in parameter list\", Token.token);\n    if (Token.token == separate_token)\n      scan(&Token);\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((funcsym != NULL) && (paramcnt != funcsym->nelems))\n    fatals(\"Parameter count mismatch for function\", funcsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(Text)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym = addglob(Text, type, NULL, S_FUNCTION, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = var_declaration_list(oldfuncsym, C_PARAM, T_COMMA, T_RPAREN);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel));\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  int offset;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text, P_STRUCT, NULL, 0, 0);\n  else\n    ctype = addunion(Text, P_UNION, NULL, 0, 0);\n  scan(&Token);\n\n  // Scan in the list of members and attach\n  // to the struct type's node\n  var_declaration_list(NULL, C_MEMBER, T_SEMI, T_RBRACE);\n  rbrace();\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->posn = genalign(m->type, offset, 1);\n    else\n      m->posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  struct symtable *ctype;\n  int type;\n\n  while (1) {\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n\n    // Get the type\n    type = parse_type(&ctype);\n\n    // We might have just parsed a struct or union\n    // declaration with no associated variable.\n    // The next token might be a ';'. Loop back if it is.\n    // XXX. I'm not happy with this as it allows\n    // \"struct fred;\" as an accepted statement\n    if ((type == P_STRUCT || type == P_UNION)\n\t&& Token.token == T_SEMI) {\n      scan(&Token);\n      continue;\n    }\n    // We have to read past the identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration\n      tree = function_declaration(type);\n\n      // Only a function prototype, no code\n      if (tree == NULL)\n\tcontinue;\n\n      // A real function, generate the assembly code for it\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, ctype, C_GLOBAL);\n      semi();\n    }\n  }\n}\n"
  },
  {
    "path": "33_Unions/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint size, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addunion(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint parse_type(struct symtable **ctype);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "33_Unions/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER\t\t\t// Member of a struct or union\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  union {\n    int size;\t\t\t// Number of elements in the symbol\n    int endlabel;\t\t// For functions, the end label\n  };\n  union {\n    int nelems;\t\t\t// For functions, # of params\n    int posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  };\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  union {\t\t\t// the symbol in the symbol table\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "33_Unions/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "33_Unions/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOLABEL, n->op);\n      genfreeregs();\n      genAST(n->right, NOLABEL, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, label));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "33_Unions/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Open up the input file\n  if ((Infile = fopen(filename, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "33_Unions/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "33_Unions/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n    case 'a':\n      return '\\a';\n    case 'b':\n      return '\\b';\n    case 'f':\n      return '\\f';\n    case 'n':\n      return '\\n';\n    case 'r':\n      return '\\r';\n    case 't':\n      return '\\t';\n    case 'v':\n      return '\\v';\n    case '\\\\':\n      return '\\\\';\n    case '\"':\n      return '\"';\n    case '\\'':\n      return '\\'';\n    default:\n      fatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n  case 'c':\n    if (!strcmp(s, \"char\"))\n      return (T_CHAR);\n    break;\n  case 'e':\n    if (!strcmp(s, \"else\"))\n      return (T_ELSE);\n    break;\n  case 'f':\n    if (!strcmp(s, \"for\"))\n      return (T_FOR);\n    break;\n  case 'i':\n    if (!strcmp(s, \"if\"))\n      return (T_IF);\n    if (!strcmp(s, \"int\"))\n      return (T_INT);\n    break;\n  case 'l':\n    if (!strcmp(s, \"long\"))\n      return (T_LONG);\n    break;\n  case 'r':\n    if (!strcmp(s, \"return\"))\n      return (T_RETURN);\n    break;\n  case 's':\n    if (!strcmp(s, \"struct\"))\n      return (T_STRUCT);\n    break;\n  case 'u':\n    if (!strcmp(s, \"union\"))\n      return (T_UNION);\n    break;\n  case 'v':\n    if (!strcmp(s, \"void\"))\n      return (T_VOID);\n    break;\n  case 'w':\n    if (!strcmp(s, \"while\"))\n      return (T_WHILE);\n    break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n  case EOF:\n    t->token = T_EOF;\n    return (0);\n  case '+':\n    if ((c = next()) == '+') {\n      t->token = T_INC;\n    } else {\n      putback(c);\n      t->token = T_PLUS;\n    }\n    break;\n  case '-':\n    if ((c = next()) == '-') {\n      t->token = T_DEC;\n    } else if (c == '>') {\n      t->token = T_ARROW;\n    } else {\n      putback(c);\n      t->token = T_MINUS;\n    }\n    break;\n  case '*':\n    t->token = T_STAR;\n    break;\n  case '/':\n    t->token = T_SLASH;\n    break;\n  case ';':\n    t->token = T_SEMI;\n    break;\n  case '{':\n    t->token = T_LBRACE;\n    break;\n  case '}':\n    t->token = T_RBRACE;\n    break;\n  case '(':\n    t->token = T_LPAREN;\n    break;\n  case ')':\n    t->token = T_RPAREN;\n    break;\n  case '[':\n    t->token = T_LBRACKET;\n    break;\n  case ']':\n    t->token = T_RBRACKET;\n    break;\n  case '~':\n    t->token = T_INVERT;\n    break;\n  case '^':\n    t->token = T_XOR;\n    break;\n  case ',':\n    t->token = T_COMMA;\n    break;\n  case '.':\n    t->token = T_DOT;\n    break;\n  case '=':\n    if ((c = next()) == '=') {\n      t->token = T_EQ;\n    } else {\n      putback(c);\n      t->token = T_ASSIGN;\n    }\n    break;\n  case '!':\n    if ((c = next()) == '=') {\n      t->token = T_NE;\n    } else {\n      putback(c);\n      t->token = T_LOGNOT;\n    }\n    break;\n  case '<':\n    if ((c = next()) == '=') {\n      t->token = T_LE;\n    } else if (c == '<') {\n      t->token = T_LSHIFT;\n    } else {\n      putback(c);\n      t->token = T_LT;\n    }\n    break;\n  case '>':\n    if ((c = next()) == '=') {\n      t->token = T_GE;\n    } else if (c == '>') {\n      t->token = T_RSHIFT;\n    } else {\n      putback(c);\n      t->token = T_GT;\n    }\n    break;\n  case '&':\n    if ((c = next()) == '&') {\n      t->token = T_LOGAND;\n    } else {\n      putback(c);\n      t->token = T_AMPER;\n    }\n    break;\n  case '|':\n    if ((c = next()) == '|') {\n      t->token = T_LOGOR;\n    } else {\n      putback(c);\n      t->token = T_OR;\n    }\n    break;\n  case '\\'':\n    // If it's a quote, scan in the\n    // literal character value and\n    // the trailing quote\n    t->intvalue = scanch();\n    t->token = T_INTLIT;\n    if (next() != '\\'')\n      fatal(\"Expected '\\\\'' at end of char literal\");\n    break;\n  case '\"':\n    // Scan in a literal string\n    scanstr(Text);\n    t->token = T_STRLIT;\n    break;\n  default:\n    // If it's a digit, scan the\n    // literal integer value in\n    if (isdigit(c)) {\n      t->intvalue = scanint(c);\n      t->token = T_INTLIT;\n      break;\n    } else if (isalpha(c) || '_' == c) {\n      // Read in a keyword or identifier\n      scanident(c, Text, TEXTLEN);\n\n      // If it's a recognised keyword, return that token\n      if ((tokentype = keyword(Text)) != 0) {\n\tt->token = tokentype;\n\tbreak;\n      }\n      // Not a recognised keyword, so it must be an identifier\n      t->token = T_IDENT;\n      break;\n    }\n    // The character isn't part of any recognised token, error\n    fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "33_Unions/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration\n      // and skip over the semicolon\n      type = parse_type(&ctype);\n      ident();\n      var_declaration(type, ctype, C_LOCAL);\n      semi();\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "33_Unions/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int size, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->size = size;\n  node->posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(node);\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_GLOBAL, size, 0);\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, size, 0);\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, size, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, size, 0);\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_STRUCT, size, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_UNION, size, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\nstatic struct symtable *findsyminlist(char *s, struct symtable *list) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "33_Unions/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:15 on line 5\n"
  },
  {
    "path": "33_Unions/tests/err.input32.c",
    "content": "Unknown variable:cow on line 4\n"
  },
  {
    "path": "33_Unions/tests/err.input33.c",
    "content": "Incompatible type to return on line 4\n"
  },
  {
    "path": "33_Unions/tests/err.input34.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4\n"
  },
  {
    "path": "33_Unions/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 4\n"
  },
  {
    "path": "33_Unions/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4\n"
  },
  {
    "path": "33_Unions/tests/err.input37.c",
    "content": "Unexpected token in parameter list:15 on line 3\n"
  },
  {
    "path": "33_Unions/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4\n"
  },
  {
    "path": "33_Unions/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 4\n"
  },
  {
    "path": "33_Unions/tests/err.input40.c",
    "content": "No return for function with non-void type on line 4\n"
  },
  {
    "path": "33_Unions/tests/err.input41.c",
    "content": "Can't return from a void function on line 3\n"
  },
  {
    "path": "33_Unions/tests/err.input42.c",
    "content": "Undeclared function:fred on line 3\n"
  },
  {
    "path": "33_Unions/tests/err.input43.c",
    "content": "Undeclared array:b on line 3\n"
  },
  {
    "path": "33_Unions/tests/err.input44.c",
    "content": "Unknown variable:z on line 3\n"
  },
  {
    "path": "33_Unions/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "33_Unions/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 3\n"
  },
  {
    "path": "33_Unions/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "33_Unions/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "33_Unions/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 6\n"
  },
  {
    "path": "33_Unions/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 6\n"
  },
  {
    "path": "33_Unions/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 4\n"
  },
  {
    "path": "33_Unions/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 5\n"
  },
  {
    "path": "33_Unions/tests/err.input56.c",
    "content": "unknown struct/union type:var1 on line 2\n"
  },
  {
    "path": "33_Unions/tests/err.input57.c",
    "content": "previously defined struct/union:fred on line 2\n"
  },
  {
    "path": "33_Unions/tests/err.input59.c",
    "content": "Undeclared variable:y on line 3\n"
  },
  {
    "path": "33_Unions/tests/err.input60.c",
    "content": "Undeclared variable:x on line 3\n"
  },
  {
    "path": "33_Unions/tests/err.input61.c",
    "content": "Undeclared variable:x on line 3\n"
  },
  {
    "path": "33_Unions/tests/input01.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "33_Unions/tests/input02.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "33_Unions/tests/input03.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "33_Unions/tests/input04.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "33_Unions/tests/input05.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "33_Unions/tests/input06.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "33_Unions/tests/input07.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "33_Unions/tests/input08.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "33_Unions/tests/input09.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "33_Unions/tests/input10.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "33_Unions/tests/input11.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "33_Unions/tests/input12.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "33_Unions/tests/input13.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "33_Unions/tests/input14.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input15.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input16.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input17.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input18.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input18a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input19.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input20.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input21.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input22.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input23.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input24.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input25.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input26.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input27.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input28.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input29.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input31.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "33_Unions/tests/input32.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "33_Unions/tests/input33.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "33_Unions/tests/input34.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input35.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "33_Unions/tests/input36.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "33_Unions/tests/input37.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "33_Unions/tests/input38.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "33_Unions/tests/input39.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "33_Unions/tests/input40.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "33_Unions/tests/input41.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "33_Unions/tests/input42.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "33_Unions/tests/input43.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "33_Unions/tests/input44.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "33_Unions/tests/input45.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "33_Unions/tests/input46.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "33_Unions/tests/input47.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "33_Unions/tests/input48.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "33_Unions/tests/input49.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "33_Unions/tests/input50.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "33_Unions/tests/input51.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "33_Unions/tests/input52.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "33_Unions/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input55.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input56.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "33_Unions/tests/input57.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "33_Unions/tests/input58.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/input59.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "33_Unions/tests/input60.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "33_Unions/tests/input61.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "33_Unions/tests/input62.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "33_Unions/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i ../lib/printint.c\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "33_Unions/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "33_Unions/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "33_Unions/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "33_Unions/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "33_Unions/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "33_Unions/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "33_Unions/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "33_Unions/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "33_Unions/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "33_Unions/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "33_Unions/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "33_Unions/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "33_Unions/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "33_Unions/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "33_Unions/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "33_Unions/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "33_Unions/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "33_Unions/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "33_Unions/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "33_Unions/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "33_Unions/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "33_Unions/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "33_Unions/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "33_Unions/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "33_Unions/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "33_Unions/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "33_Unions/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "33_Unions/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "33_Unions/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "33_Unions/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "33_Unions/tests/out.input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "33_Unions/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "33_Unions/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "33_Unions/tests/out.input55.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "33_Unions/tests/out.input58.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "33_Unions/tests/out.input62.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "33_Unions/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "33_Unions/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "33_Unions/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "33_Unions/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return ((type & 0xf) == 0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\t// XXX Fix soon\n    rsize = typesize(rtype, NULL);\t// XXX Fix soon\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/Makefile",
    "content": "HSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out\n\ntest: cwj tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: compn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "34_Enums_and_Typedefs/Readme.md",
    "content": "# Part 34: Enums and Typedefs\n\nI decided to implement both enums and typedefs in this part of our\ncompiler writing journey, as each one was quite small.\n\nWe already covered the design aspects of enums back in part 30. To revise\nbriefly, enums are just named integer literals. There were two issues to\ndeal with:\n\n + we cannot redefine an enum type name, and\n + we cannot redefine a named enum value\n\nAs examples of the above:\n\n```c\nenum fred { x, y, z };\nenum fred { a, b };             // fred is redefined\nenum jane { x, y };             // x and y are redefined\n```\n\nAs you can see above, a list of enumerated values only has identifier names\nand no types: it means we can't reuse our existing variable declaration\nparsing code. We will have to write our own parsing code here.\n\n## New Keywords and Tokens\n\nI've added two new keywords, 'enum' and 'typedef' to the grammar along\nwith two tokens, T_ENUM and T_TYPEDEF. Browse through the code in `scan.c`\nfor details.\n\n## Symbol Table Lists for Enums and Typedefs\n\nWe need to record the details of the declared enums and typedefs, so there\nare two new symbol table lists in `data.h`:\n\n```c\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n```\n\nand in `sym.c` there are associated functions to add entries to each list\nand to search each list for specific names. Nodes in these lists are\nmarked as being one of (from `defs.h`):\n\n```c\n  C_ENUMTYPE,                   // A named enumeration type\n  C_ENUMVAL,                    // A named enumeration value\n  C_TYPEDEF                     // A named typedef\n```\n\nOK, so two lists but three node classes, what's going on? It turns out\nthat enum values (like `x` and `y` in the examples at the top) don't\nbelong to any specific enum type. Also, enum type names (like `fred` and\n`jane` in the examples at the top) don't really do anything, but we do\nhave to prevent redefinitions of them.\n\nI'm using the one enum symbol table list to hold both the C_ENUMTYPE and\nthe C_ENUMVAL nodes in the same lists. Using the examples near the top,\nwe would have:\n\n```\n   fred           x            y            z\nC_ENUMTYPE -> C_ENUMVAL -> C_ENUMVAL -> C_ENUMVAL\n                  0            1            2\n```\n\nThis also means that, when we are searching the enum symbol table list,\nwe need the ability to search for C_ENUMTYPEs or for C_ENUMVALs.\n\n## Parsing Enum Declarations\n\nBefore I give the code to do this, let's just look at some examples\nof what we need to parse:\n\n```c\nenum fred { a, b, c };                  // a is 0, b is 1, c is 2\nenum foo  { d=2, e=6, f };              // d is 2, e is 6, f is 7\nenum bar  { g=2, h=6, i } var1;         // var1 is really an int\nenum      { j, k, l }     var2;         // var2 is really an int\n```\n\nFirstly, where does enum parsing get attached to our existing parsing code?\nAs with structs and unions, in the code that parses types (in `decl.c`):\n\n```c\n// Parse the current token and return\n// a primitive type enum value and a pointer\n// to any composite type.\n// Also scan in the next token\nint parse_type(struct symtable **ctype) {\n  int type;\n  switch (Token.token) {\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1\n      ...\n    case T_ENUM:\n      type = P_INT;             // Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n        type = -1;\n      break;\n  }\n  ...\n}\n```\n\nI've changed the return value of `parse_type()` to help identify when\nit was a declaration of a struct, union, enum or typedef and not\nan actual type (followed by an identifier).\n\nLet's now look at the `enum_declaration()` code in stages.\n\n```c\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);        // As it gets tromped soon\n    scan(&Token);\n  }\n```\n\nWe only have one global variable, `Text`, to hold a scanned-in word, and\nwe have to be able to parse `enum foo var1`. If we scan in the token after\nthe `foo`, we will lose the `foo` string. So we need to `strdup()` this.\n\n```c\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n```\n\nWe've hit a declaration like `enum foo var1` and not `enum foo { ...`.\nTherefore `foo` must already exist as a known enum type. We can return\nwith no value, as the type of every enum is P_INT, which is set in the\ncode that calls `enum_declaration()`.\n\n```c\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n```\n\nNow we are parsing something like `enum foo { ...`, so we must check\nthat `foo` has not already been declared as an enum type.\n\n```c\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n```\n\nAgain, we `strdup()` the enum value identifier.\nWe also check that this enum value identifier hasn't already been defined.\n\n```c\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n        fatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n```\n\nThis is why we had to `strdup()` as the scanning of an integer literal\nwill walk over the `Text` global variable. We scan in the '=' and integer literal\ntokens here and set the `intval` variable to be the integer literal value.\n\n```c\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);                 // Skip over the right curly bracket\n}\n```\n\nWe now have the enum value's name and its value in `intval`. We can\nadd this to the enum symbol table list with `addenum()`. We also increment\n`intval` to be ready for the next enum value identifier.\n\n## Accessing Enum Names\n\nWe now have the code to parse the list of enum value names and store\ntheir integer literal values in the symbol table. How and when do we\nsearch for them and use them?\n\nWe have to do this at the point where we could be using a variable name\nin an expression. If we find an enum name, we convert it into an A_INTLIT\nAST node with a specific value. The location to do this is `postfix()`\nin `expr.c`\n\n```c\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->posn));\n  }\n  ...\n}\n```\n\n## Testing the Functionality\n\nAll done! There are several test programs that confirm we are spotting\nredefined enum types and names, but the `test/input63.c` code demonstrates\nenums working:\n\n```c\nint printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n```\n\nwhich adds `carrot + pear + mango` (i.e. 3+10+12) and prints out 25.\n\n## Typedefs\n\nThat's enums done. Now we look at typedefs. The basic grammar of a typedef\ndeclaration is:\n\n```\ntypedef_declaration: 'typedef' identifier existing_type\n                   | 'typedef' identifier existing_type variable_name\n                   ;\n```\n\nThus, once we parse the `typedef` keyword, we can parse the following type\nand build a C_TYPEDEF symbol node with the name. We can store the `type` and\n`ctype` of the actual type in this symbol node.\n\nThe parsing code is nice and simple. We hook into `parse_type()` in `decl.c`:\n\n```c\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n        type = -1;\n      break;\n```\n\nHere is the `typedef_declaration()` code. Note that it returns the actual\n`type` and `ctype` in case the declaration is followed by a variable name.\n\n```c\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nint typedef_declaration(struct symtable **ctype) {\n  int type;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype);\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype, 0, 0);\n  scan(&Token);\n  return (type);\n}\n```\n\nThe code should be straight-forward but note the recursive call back to\n`parse_type()`: we already have the code to parse the type definition\nafter the name of the typedef.\n\n## Searching and Using Typedef Definitions\n\nWe now have a list of typedef definitions in a symbol table list.\nHow do we use these definitions? We effectively have added new type keywords\nto our grammar, e.g.\n\n```c\nFILE    *zin;\nint32_t cost;\n```\n\nIt just means that when we are parsing a type and we hit a keyword that\nwe don't recognise, we can look that work up in the typedef list. So,\nwe get to modify `parse_type()` again:\n\n```c\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n```\n\nBoth `type` and `ctype` are returned by `type_of_typedef()`:\n\n```c\n// Given a typedef name, return the type it represents\nint type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n```\n\nNote that, as yet, I haven't written the code to be \"recursive\". For example,\nthe current code won't parse this example:\n\n```c\ntypedef int FOO;\ntypedef FOO BAR;\nBAR x;                  // x is of type BAR -> type FOO -> type int\n```\n\nBut it does compile `tests/input68.c`:\n\n```c\nint printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n```\n\nwith both `int` redefined as type `FOO` and a struct redefined as type `BAR`.\n\n\n## Conclusion and What's Next\n\nIn this part of our compiler writing journey, we added support for both\nenums and typedefs. Both were relatively easy to do, even though we did\nhave to write a fair bit of parsing code for the enums. I guess I was\nspoiled when I could reuse the same parsing code for variable lists,\nstruct member lists and union member lists!\n\nThe code to add typedefs was really nice and simple. I do need to\nadd to code to follow typedefs of typedefs: that also should be simple.\n\nIn the next part of our compiler writing journey, I think it's time we\nbring in the C pre-processor. Now that we have structs, unions, enums\nand typedefs, we should be able to write a bunch of *header files*\nwith definitions of some of the common Unix/Linux library functions.\nThen we will be able to include them in our source files and write\nsome really useful programs. [Next step](../35_Preprocessor/Readme.md)\n"
  },
  {
    "path": "34_Enums_and_Typedefs/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch(type) {\n    case P_CHAR: return (offset);\n    case P_INT:\n    case P_LONG: break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment= 4;\n  offset = (offset + direction * (alignment-1)) & ~(alignment-1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      for (int i=0; i < size; i++)\n        fprintf(Outfile, \"\\t.byte\\t0\\n\");\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch(type) {\n    case P_CHAR: return (offset);\n    case P_INT:\n    case P_LONG: break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment= 4;\n  offset = (offset + direction * (alignment-1)) & ~(alignment-1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  // original version\n  for (int i = 0; i < node->size; i++) {\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(size) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", node->size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", node->size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", node->size);\n      break;\n    default:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "34_Enums_and_Typedefs/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic void enum_declaration(void);\nint typedef_declaration(struct symtable **ctype);\nint type_of_typedef(char *name, struct symtable **ctype);\n\n\n// Parse the current token and return\n// a primitive type enum value and a pointer\n// to any composite type.\n// Also scan in the next token\nint parse_type(struct symtable **ctype) {\n  int type;\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type.\n// class is the variable's class\n// Return the pointer to variable's entry in the symbol table\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class) {\n  struct symtable *sym = NULL;\n\n  // See if this has already been declared\n  switch (class) {\n    case C_GLOBAL:\n      if (findglob(Text) != NULL)\n\tfatals(\"Duplicate global variable declaration\", Text);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(Text) != NULL)\n\tfatals(\"Duplicate local variable declaration\", Text);\n    case C_MEMBER:\n      if (findmember(Text) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", Text);\n  }\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      switch (class) {\n\tcase C_GLOBAL:\n\t  sym =\n\t    addglob(Text, pointer_to(type), ctype, S_ARRAY, Token.intvalue);\n\t  break;\n\tcase C_LOCAL:\n\tcase C_PARAM:\n\tcase C_MEMBER:\n\t  fatal\n\t    (\"For now, declaration of non-global arrays is not implemented\");\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    switch (class) {\n      case C_GLOBAL:\n\tsym = addglob(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_LOCAL:\n\tsym = addlocl(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_PARAM:\n\tsym = addparm(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_MEMBER:\n\tsym = addmemb(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n    }\n  }\n  return (sym);\n}\n\n// var_declaration_list: <null>\n//           | variable_declaration\n//           | variable_declaration separate_token var_declaration_list ;\n//\n// When called to parse function parameters, separate_token is ','.\n// When called to parse members of a struct/union, separate_token is ';'.\n//\n// Parse a list of variables.\n// Add them as symbols to one of the symbol table lists, and return the\n// number of variables. If funcsym is not NULL, there is an existing function\n// prototype, so compare each variable's type against this prototype.\nstatic int var_declaration_list(struct symtable *funcsym, int class,\n\t\t\t\tint separate_token, int end_token) {\n  int type;\n  int paramcnt = 0;\n  struct symtable *protoptr = NULL;\n  struct symtable *ctype;\n\n  // If there is a prototype, get the pointer\n  // to the first prototype parameter\n  if (funcsym != NULL)\n    protoptr = funcsym->member;\n\n  // Loop until the final end token\n  while (Token.token != end_token) {\n    // Get the type and identifier\n    type = parse_type(&ctype);\n    ident();\n\n    // Check that this type matches the prototype if there is one\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    } else {\n      // Add a new parameter to the right symbol table list, based on the class\n      var_declaration(type, ctype, class);\n    }\n    paramcnt++;\n\n    // Must have a separate_token or ')' at this point\n    if ((Token.token != separate_token) && (Token.token != end_token))\n      fatald(\"Unexpected token in parameter list\", Token.token);\n    if (Token.token == separate_token)\n      scan(&Token);\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((funcsym != NULL) && (paramcnt != funcsym->nelems))\n    fatals(\"Parameter count mismatch for function\", funcsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(Text)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym = addglob(Text, type, NULL, S_FUNCTION, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = var_declaration_list(oldfuncsym, C_PARAM, T_COMMA, T_RPAREN);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel));\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  int offset;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text, P_STRUCT, NULL, 0, 0);\n  else\n    ctype = addunion(Text, P_UNION, NULL, 0, 0);\n  scan(&Token);\n\n  // Scan in the list of members and attach\n  // to the struct type's node\n  var_declaration_list(NULL, C_MEMBER, T_SEMI, T_RBRACE);\n  rbrace();\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->posn = genalign(m->type, offset, 1);\n    else\n      m->posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nint typedef_declaration(struct symtable **ctype) {\n  int type;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype);\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype, 0, 0);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nint type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  struct symtable *ctype;\n  int type;\n\n  while (1) {\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n\n    // Get the type\n    type = parse_type(&ctype);\n\n    // We might have just parsed a struct, union or enum\n    // declaration with no associated variable.\n    // The next token might be a ';'. Loop back if it is.\n    // XXX: I'm not happy with this as it allows\n    // \"struct fred;\" as an accepted statement\n    if (type == -1) {\n      semi();\n      continue;\n    }\n    // We have to read past the identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration\n      tree = function_declaration(type);\n\n      // Only a function prototype, no code\n      if (tree == NULL)\n\tcontinue;\n\n      // A real function, generate the assembly code for it\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, ctype, C_GLOBAL);\n      semi();\n    }\n  }\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint size, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addunion(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint parse_type(struct symtable **ctype);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "34_Enums_and_Typedefs/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  union {\n    int size;\t\t\t// Number of elements in the symbol\n    int endlabel;\t\t// For functions, the end label\n  };\n  union {\n    int nelems;\t\t\t// For functions, # of params\n    int posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  };\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  union {\t\t\t// the symbol in the symbol table\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "34_Enums_and_Typedefs/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOLABEL, n->op);\n      genfreeregs();\n      genAST(n->right, NOLABEL, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, label));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Open up the input file\n  if ((Infile = fopen(filename, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d\\n\", s, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d\\n\", s1, s2, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d\\n\", s, d, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d\\n\", s, c, Line);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n    case 'a':\n      return '\\a';\n    case 'b':\n      return '\\b';\n    case 'f':\n      return '\\f';\n    case 'n':\n      return '\\n';\n    case 'r':\n      return '\\r';\n    case 't':\n      return '\\t';\n    case 'v':\n      return '\\v';\n    case '\\\\':\n      return '\\\\';\n    case '\"':\n      return '\"';\n    case '\\'':\n      return '\\'';\n    default:\n      fatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n  case 'c':\n    if (!strcmp(s, \"char\"))\n      return (T_CHAR);\n    break;\n  case 'e':\n    if (!strcmp(s, \"else\"))\n      return (T_ELSE);\n    if (!strcmp(s, \"enum\"))\n      return (T_ENUM);\n    break;\n  case 'f':\n    if (!strcmp(s, \"for\"))\n      return (T_FOR);\n    break;\n  case 'i':\n    if (!strcmp(s, \"if\"))\n      return (T_IF);\n    if (!strcmp(s, \"int\"))\n      return (T_INT);\n    break;\n  case 'l':\n    if (!strcmp(s, \"long\"))\n      return (T_LONG);\n    break;\n  case 'r':\n    if (!strcmp(s, \"return\"))\n      return (T_RETURN);\n    break;\n  case 's':\n    if (!strcmp(s, \"struct\"))\n      return (T_STRUCT);\n    break;\n  case 't':\n    if (!strcmp(s, \"typedef\"))\n      return (T_TYPEDEF);\n    break;\n  case 'u':\n    if (!strcmp(s, \"union\"))\n      return (T_UNION);\n    break;\n  case 'v':\n    if (!strcmp(s, \"void\"))\n      return (T_VOID);\n    break;\n  case 'w':\n    if (!strcmp(s, \"while\"))\n      return (T_WHILE);\n    break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n  case EOF:\n    t->token = T_EOF;\n    return (0);\n  case '+':\n    if ((c = next()) == '+') {\n      t->token = T_INC;\n    } else {\n      putback(c);\n      t->token = T_PLUS;\n    }\n    break;\n  case '-':\n    if ((c = next()) == '-') {\n      t->token = T_DEC;\n    } else if (c == '>') {\n      t->token = T_ARROW;\n    } else {\n      putback(c);\n      t->token = T_MINUS;\n    }\n    break;\n  case '*':\n    t->token = T_STAR;\n    break;\n  case '/':\n    t->token = T_SLASH;\n    break;\n  case ';':\n    t->token = T_SEMI;\n    break;\n  case '{':\n    t->token = T_LBRACE;\n    break;\n  case '}':\n    t->token = T_RBRACE;\n    break;\n  case '(':\n    t->token = T_LPAREN;\n    break;\n  case ')':\n    t->token = T_RPAREN;\n    break;\n  case '[':\n    t->token = T_LBRACKET;\n    break;\n  case ']':\n    t->token = T_RBRACKET;\n    break;\n  case '~':\n    t->token = T_INVERT;\n    break;\n  case '^':\n    t->token = T_XOR;\n    break;\n  case ',':\n    t->token = T_COMMA;\n    break;\n  case '.':\n    t->token = T_DOT;\n    break;\n  case '=':\n    if ((c = next()) == '=') {\n      t->token = T_EQ;\n    } else {\n      putback(c);\n      t->token = T_ASSIGN;\n    }\n    break;\n  case '!':\n    if ((c = next()) == '=') {\n      t->token = T_NE;\n    } else {\n      putback(c);\n      t->token = T_LOGNOT;\n    }\n    break;\n  case '<':\n    if ((c = next()) == '=') {\n      t->token = T_LE;\n    } else if (c == '<') {\n      t->token = T_LSHIFT;\n    } else {\n      putback(c);\n      t->token = T_LT;\n    }\n    break;\n  case '>':\n    if ((c = next()) == '=') {\n      t->token = T_GE;\n    } else if (c == '>') {\n      t->token = T_RSHIFT;\n    } else {\n      putback(c);\n      t->token = T_GT;\n    }\n    break;\n  case '&':\n    if ((c = next()) == '&') {\n      t->token = T_LOGAND;\n    } else {\n      putback(c);\n      t->token = T_AMPER;\n    }\n    break;\n  case '|':\n    if ((c = next()) == '|') {\n      t->token = T_LOGOR;\n    } else {\n      putback(c);\n      t->token = T_OR;\n    }\n    break;\n  case '\\'':\n    // If it's a quote, scan in the\n    // literal character value and\n    // the trailing quote\n    t->intvalue = scanch();\n    t->token = T_INTLIT;\n    if (next() != '\\'')\n      fatal(\"Expected '\\\\'' at end of char literal\");\n    break;\n  case '\"':\n    // Scan in a literal string\n    scanstr(Text);\n    t->token = T_STRLIT;\n    break;\n  default:\n    // If it's a digit, scan the\n    // literal integer value in\n    if (isdigit(c)) {\n      t->intvalue = scanint(c);\n      t->token = T_INTLIT;\n      break;\n    } else if (isalpha(c) || '_' == c) {\n      // Read in a keyword or identifier\n      scanident(c, Text, TEXTLEN);\n\n      // If it's a recognised keyword, return that token\n      if ((tokentype = keyword(Text)) != 0) {\n\tt->token = tokentype;\n\tbreak;\n      }\n      // Not a recognised keyword, so it must be an identifier\n      t->token = T_IDENT;\n      break;\n    }\n    // The character isn't part of any recognised token, error\n    fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration\n      // and skip over the semicolon\n      type = parse_type(&ctype);\n      ident();\n      var_declaration(type, ctype, C_LOCAL);\n      semi();\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int size, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->size = size;\n  node->posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(node);\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_GLOBAL, size, 0);\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, size, 0);\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, size, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, size, 0);\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_STRUCT, size, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_UNION, size, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_TYPEDEF, size, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:15 on line 5\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input32.c",
    "content": "Unknown variable:cow on line 4\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input33.c",
    "content": "Incompatible type to return on line 4\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input34.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 4\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input37.c",
    "content": "Unexpected token in parameter list:15 on line 3\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 4\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input40.c",
    "content": "No return for function with non-void type on line 4\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input41.c",
    "content": "Can't return from a void function on line 3\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input42.c",
    "content": "Undeclared function:fred on line 3\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input43.c",
    "content": "Undeclared array:b on line 3\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input44.c",
    "content": "Unknown variable:z on line 3\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 3\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 3\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 6\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 6\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 4\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 5\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input56.c",
    "content": "unknown struct/union type:var1 on line 2\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input57.c",
    "content": "previously defined struct/union:fred on line 2\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input59.c",
    "content": "Undeclared variable:y on line 3\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input60.c",
    "content": "Undeclared variable:x on line 3\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input61.c",
    "content": "Undeclared variable:x on line 3\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input64.c",
    "content": "undeclared enum type::fred on line 1\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input65.c",
    "content": "enum type redeclared::fred on line 2\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input66.c",
    "content": "enum value redeclared::z on line 2\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input68.c",
    "content": "redefinition of typedef:FOO on line 2\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/err.input69.c",
    "content": "unknown type:FLOO on line 2\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input01.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input02.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input03.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input04.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input05.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input06.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input07.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input08.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input09.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input10.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input11.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input12.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input13.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input14.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input15.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input16.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input17.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input18.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input18a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input19.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input20.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input21.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input22.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input23.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input24.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input25.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input26.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input27.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input28.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input29.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input31.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input32.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input33.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input34.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input35.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input36.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input37.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input38.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input39.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input40.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input41.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input42.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input43.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input44.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input45.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input46.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input47.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input48.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input49.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input50.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input51.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input52.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input55.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input56.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input57.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input58.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input59.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input60.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input61.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input62.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input63.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input64.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input65.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input66.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input67.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input68.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/input69.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i ../lib/printint.c\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input55.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input58.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input62.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input63.c",
    "content": "25\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/out.input67.c",
    "content": "5\n17\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "34_Enums_and_Typedefs/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "34_Enums_and_Typedefs/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return ((type & 0xf) == 0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\t// XXX Fix soon\n    rsize = typesize(rtype, NULL);\t// XXX Fix soon\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "35_Preprocessor/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "35_Preprocessor/Readme.md",
    "content": "# Part 35: The C Pre-Processor\n\nIn this part of our compiler writing journey, I've added support for\nan external C pre-processor, and I also added the `extern` keyword to\nour language.\n\nWe've reached the point where we can write\n[header files](https://www.tutorialspoint.com/cprogramming/c_header_files.htm)\nfor our programs, and also put comments in them. I must admit, this feels good.\n\n## The C Pre-Processor\n\nI don't want to write about the C pre-processor itself, even though is\na very important part of any C environment. Instead, I'll point you at\nthese two articles to read:\n\n + [C Preprocessor](https://en.wikipedia.org/wiki/C_preprocessor) at *Wikipedia*\n + [C Preprocessor and Macros](https://www.programiz.com/c-programming/c-preprocessor-macros) at *www.programiz.com*\n\n## Integrating the C Pre-Processor\n\nIn other compilers like [SubC](http://www.t3x.org/subc/), the pre-processor\nis built right into the language. Here I've decided to use the external\nsystem C pre-processor which is usually\nthe [Gnu C pre-processor](https://gcc.gnu.org/onlinedocs/cpp/).\n\nBefore I show you how I've done this, firstly we need to look at the\nlines that the pre-processor inserts as part of its operation.\n\nConsider this short program (with lines numbered):\n\n```c\n1 #include <stdio.h>\n2 \n3 int main() {\n4   printf(\"Hello world\\n\");\n5   return(0);\n6 }\n```\n\nHere is what we (the compiler) might receive from the pre-processor\nafter it processes this file:\n\n```c\n# 1 \"z.c\"\n# 1 \"<built-in>\"\n# 1 \"<command-line>\"\n# 1 \"z.c\"\n# 1 \"include/stdio.h\" 1\n# 1 \"include/stddef.h\" 1\n\ntypedef long size_t;\n# 5 \"include/stdio.h\" 2\n\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\n...\n# 2 \"z.c\" 2\n\nint main() {\n  printf(\"Hello world\\n\");\n  return(0);\n}\n```\n\nEach pre-processor line starts with a '#', then the number of the following\nline, then the name of the file from where this line comes from. The numbers\nat the end of some of the lines I don't really know what they are. I suspect,\nwhen one file includes another, they represent the line number of the file\nthat did the including.\n\nHere is how I'm going to integrate the pre-processor with our compiler.\nI'm going to use `popen()` to open up a pipe from a process which is\nthe pre-processor, and we will tell the pre-processor to work on our\ninput file. Then we will modify the lexical scanner to identify the\npre-processor lines and set the current line number and name of the file\nbeing processed.\n\n## Modifications to `main.c`\n\nWe have a new global variable, `char *Infilename`, defined in `data.h`.\nIn the `do_compile()` function in `main.c` we now do this:\n\n```c\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n  ...\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n```\n\nwhich I think is a straight-forward piece of code, except that I haven't\nexplained where `CPPCMD` and `INCDIR` come from.\n\n`CPPCMD` is defined as the name of the pre-processor command in `defs.h`:\n\n```c\n#define CPPCMD \"cpp -nostdinc -isystem \"\n```\n\nThis tells the Gnu pre-processor to not use the standard include directory\n`/usr/include`: instead, `-isystem` tells the pre-processor to use the\nnext thing on the command line which is `INCDIR`.\n\n`INCDIR` is actually defined in the `Makefile`, as this is a common place\nto put things that can be changed at configuration time:\n\n```make\n# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n```\n\nThe compiler binary is now compiled with this `Makefile` rule:\n\n```make\ncwj: $(SRCS) $(HSRCS)\n        cc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n```\n\nand this passes the `/tmp/include` value in to the compilation as `INCDIR`.\nNow, when does `/tmp/include` get created, and what gets put there?\n\n## Our First Set of Header Files\n\nIn the `include/` directory in this area, I've made a start on some\nheader files that are plain enough for our compiler to digest. We can't\nuse the real system header files, as they contain lines like:\n\n```c\nextern int _IO_feof (_IO_FILE *__fp) __attribute__ ((__nothrow__ , __leaf__));\nextern int _IO_ferror (_IO_FILE *__fp) __attribute__ ((__nothrow__ , __leaf__));\n```\n\nwhich would cause our compiler to have a fit! There is now a rule in the\n`Makefile` to copy our own header files to the `INCDIR` directory:\n\n```make\ninstall: cwj\n        mkdir -p $(INCDIR)\n        rsync -a include/. $(INCDIR)\n        cp cwj $(BINDIR)\n        chmod +x $(BINDIR)/cwj\n```\n\n## Scanning the Pre-Processor Input\n\nSo now we are reading the pre-processor output from working on the input file,\nand not reading from the file directly. We now need to recognise\npre-processor lines and set the number of the next line and the file's\nname where the line came from.\n\nI've modified the scanner to do this, as this already deals with incrementing\nthe line number. So in `scan.c`, I've made this change to the `scan()`\nfunction:\n\n```c\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {                        // Use the character put\n    c = Putback;                        // back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);                    // Read from input file\n\n  while (c == '#') {                    // We've hit a pre-processor statement\n    scan(&Token);                       // Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);                       // Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {               // If this is a real filename\n      if (strcmp(Text, Infilename))     // and not the one we have now\n        Infilename = strdup(Text);      // save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n'); // Skip to the end of the line\n    c = fgetc(Infile);                  // and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;                             // Increment line count\n  return (c);\n}\n```\n\nWe use a 'while' loop because there can be successive pre-processor lines.\nWe are fortunate that we can call `scan()` recursively to scan in both\nthe line number as a T_INTLIT and the file's name as a T_STRLIT.\n\nThe code ignores filenames that are enclosed in '<' ... '>', as these don't\nrepresent real filenames. We do have to `strdup()` the file's name as it\nis in the global `Text` variable which will get overwritten. However, if\nthe name in `Text` is already what's in `Infilename`, we don't need to\nduplicate it.\n\nOnce we have the line number and filename, we read up to and one character\npast the end of the line, then go back to our original character scanning code.\n\nAnd that turned out to be all that was needed to integrate the C pre-processor\nwith our compiler. I had worried that it would be complex to do this, but it\nwasn't.\n\n## Preventing Unwanted Function/Variable Redeclarations\n\nMany header files include other header files, so there is a strong chance\nthat one header file might get included multiple times. This would cause\nredeclarations of the same function and/or global variable.\n\nTo prevent this, I'm using the normal header mechanism of defining a\nheader-specific macro the first time a header file is included. This then\nprevents the contents of the header file being included a second time.\n\nAs an example, here is what is currently in `include/stdio.h`:\n\n```c\n#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\n\n#endif  // _STDIO_H_\n```\n\nOnce `_STDIO_H_` is defined, it prevents this file's contents from being\nincluded a second time.\n\n## The `extern` Keyword\n\nNow that we have a working pre-processor, I thought it would be time to\nadd the `extern` keyword to the language. This would allow us to define\na global variable but not generate any storage for it: the assumption is\nthat the variable has been declared global in another source file.\n\nThe addition of `extern` actually has an impact across several files.\nNot a big impact, but a widespread impact. Let's see this.\n\n### A New Token and Keyword\n\nSo, we have a new keyword `extern` and a new token T_EXTERN in `scan.c`.\nAs always, the code is there for you to read.\n\n### A New Class\n\nIn `defs.h` we have a new storage class:\n\n```c\n// Storage classes\nenum {\n  C_GLOBAL = 1,                 // Globally visible symbol\n  ...\n  C_EXTERN,                     // External globally visible symbol\n  ...\n};\n```\n\nThe reason I put this in is because we already have this code for\nglobal symbols in `sym.c`:\n\n```c\n// Create a symbol node to be added to a symbol table list.\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n                        int stype, int class, int size, int posn) {\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  // Fill in the values\n  ...\n    // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(node);\n```\n\nWe want `extern` symbols added to the global list, but we don't want to call\n`genglobsym()` to create the storage for them. So, we need to call\n`newsym()` with a class that isn't C_GLOBAL.\n\n### Changes to `sym.c`\n\nTo this end, I've modified `addglob()` to take a `class` argument which is\npassed to `newsym()`:\n\n```c\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n                         int stype, int class, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, size, 0);\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n```\n\nThis means that, everywhere that we call `addglob()` in the compiler,\nwe now must pass in a `class` value. Before, `addglob()` would explicitly\npass C_GLOBAL to `newsym()`. Now, we must pass the `class` value we want\nto `addglob()`.\n\n### The `extern` Keyword and Our Grammar\n\nIn terms of the grammar of our language, I'm going to enforce the rule\nthat the `extern` keyword must come before any other words in a type\ndescription. Later on, I'll add `static` to the list of words. The\n[BNF Grammar for C](https://www.lysator.liu.se/c/ANSI-C-grammar-y.html)\nthat we saw in past parts has these production rules:\n\n```\nstorage_class_specifier\n        : TYPEDEF\n        | EXTERN\n        | STATIC\n        | AUTO\n        | REGISTER\n        ;\n\ntype_specifier\n        : VOID\n        | CHAR\n        | SHORT\n        | INT\n        | LONG\n        | FLOAT\n        | DOUBLE\n        | SIGNED\n        | UNSIGNED\n        | struct_or_union_specifier\n        | enum_specifier\n        | TYPE_NAME\n        ;\n\ndeclaration_specifiers\n        : storage_class_specifier\n        | storage_class_specifier declaration_specifiers\n        | type_specifier\n        | type_specifier declaration_specifiers\n        | type_qualifier\n        | type_qualifier declaration_specifiers\n        ;\n\n```\n\nwhich I think allows `extern` to come anywhere in the type specification.\nOh well, we are building a subset of the C language here!\n\n### Parsing the `extern` Keyword\n\nAs with the last five or six parts of this journey, I've made changes\nto `parse_type()` in `decl.c` again:\n\n```c\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic=1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN: *class= C_EXTERN; scan(&Token); break;\n      default: exstatic= 0;\n    }\n  }\n  ...\n}\n```\n\nNote now that `parse_type()` has a second parameter, `int *class`.\nThis allows the caller to pass in the initial storage class for\nthe type (probably C_GLOBAL, G_LOCAL or C_PARAM). If we see the\n`extern` keyword in `parse_type()`, we can change to become T_EXTERN.\nAlso apologies, I couldn't think of a good name for the boolean flag\nthat controls the 'while' loop.\n\n### The `parse_type()` and `addglob()` Callers\n\nSo we've modified the arguments to both `parse_type()` and `addglob()`. Now\nwe have to find everywhere in the compiler where both functions are called,\nand ensure we pass a suitable `class` value to both of them.\n\nIn `var_declaration_list()` in `decl.c` where we are parsing a list of\nvariables or parameters, we already get the storage class for these variables:\n\n```c\nstatic int var_declaration_list(struct symtable *funcsym, int class,\n                                int separate_token, int end_token);\n```\n\nSo we can pass the `class` to `parse_type()` which may change it, then\ncall `var_declaration()` with the actual class:\n\n```c\n    ...\n    // Get the type and identifier\n    type = parse_type(&ctype, &class);\n    ident();\n    ...\n    // Add a new parameter to the right symbol table list, based on the class\n    var_declaration(type, ctype, class);\n```\n\nAnd in `var_declaration()`:\n\n```c\n      switch (class) {\n        case C_EXTERN:\n        case C_GLOBAL:\n          sym = addglob(Text, type, ctype, S_VARIABLE, class, 1);\n        ...\n      }\n```\n\nFor local variables, we need to turn our attention to `single_statement()`\nin `stmt.c`. I also should, at this point, say that I'd previously forgot\nto add the cases for structs, unions, enums and typedefs here.\n\n```c\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type, class= C_LOCAL;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not do the default code in this switch statement.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL)\n        return (binexpr(0));\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration\n      // and skip over the semicolon\n      type = parse_type(&ctype, &class);\n      ident();\n      var_declaration(type, ctype, class);\n      semi();\n      return (NULL);            // No AST generated here\n      ...\n   }\n   ...\n}\n```\n\nNote that we start with `class= C_LOCAL`, but it might get modified\nby `parse_type()` before being passed to `var_declaration()`. This allows\nus to write code that looks like:\n\n```c\nint main() {\n  extern int foo;\n  ...\n}\n```\n\n## Testing the Code\n\nI've got one test program, `test/input70.c` which uses one of our new\nheader files to confirm that the pre-processor works:\n\n```c\n#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n```\n\nI was hoping that `errno` was still an ordinary integer so that I could\ndeclare `extern int errno;` in `include/errno.h`. But, apparently,\n`errno` is now a function and not a global integer variable. I think\nthis tells you a) how old I am and b) how long it is since I've written\nC code.\n\n## Conclusion and What's Next\n\nI feel like we have hit another milestone here. We now have external\nvariables and header files. This also means that, *finally*, we can\nput comments into our source files. That really makes me happy.\n\nWe are up to just over 4,100 lines of code, of which about 2,800 lines\nare not comments and not whitespace. I have no idea exactly how many more\nlines of code we'll need to make the compiler self-compiling, but I'm going\nto hazard a guess of between 7,000 to 9,000 lines. We'll see!\n\nIn the next part of our compiler writing journey, we will add the `break`\nand `continue` keywords to our loop constructs. [Next step](../36_Break_Continue/Readme.md)\n"
  },
  {
    "path": "35_Preprocessor/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch(type) {\n    case P_CHAR: return (offset);\n    case P_INT:\n    case P_LONG: break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment= 4;\n  offset = (offset + direction * (alignment-1)) & ~(alignment-1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      for (int i=0; i < size; i++)\n        fprintf(Outfile, \"\\t.byte\\t0\\n\");\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "35_Preprocessor/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "35_Preprocessor/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch(type) {\n    case P_CHAR: return (offset);\n    case P_INT:\n    case P_LONG: break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment= 4;\n  offset = (offset + direction * (alignment-1)) & ~(alignment-1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  // original version\n  for (int i = 0; i < node->size; i++) {\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(size) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", node->size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", node->size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", node->size);\n      break;\n    default:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "35_Preprocessor/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "35_Preprocessor/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic void enum_declaration(void);\nint typedef_declaration(struct symtable **ctype);\nint type_of_typedef(char *name, struct symtable **ctype);\n\n\n// Parse the current token and return a\n// primitive type enum value, a pointer\n// to any composite type and possibly\n// modify the class of the type.\n// Also scan in the next token.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic=1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN: *class= C_EXTERN; scan(&Token); break;\n      default: exstatic= 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type.\n// class is the variable's class\n// Return the pointer to variable's entry in the symbol table\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class) {\n  struct symtable *sym = NULL;\n\n  // See if this has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      if (findglob(Text) != NULL)\n\tfatals(\"Duplicate global variable declaration\", Text);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(Text) != NULL)\n\tfatals(\"Duplicate local variable declaration\", Text);\n    case C_MEMBER:\n      if (findmember(Text) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", Text);\n  }\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      switch (class) {\n\tcase C_EXTERN:\n\tcase C_GLOBAL:\n\t  sym =\n\t    addglob(Text, pointer_to(type), ctype, S_ARRAY, class, Token.intvalue);\n\t  break;\n\tcase C_LOCAL:\n\tcase C_PARAM:\n\tcase C_MEMBER:\n\t  fatal\n\t    (\"For now, declaration of non-global arrays is not implemented\");\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    switch (class) {\n      case C_EXTERN:\n      case C_GLOBAL:\n\tsym = addglob(Text, type, ctype, S_VARIABLE, class, 1);\n\tbreak;\n      case C_LOCAL:\n\tsym = addlocl(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_PARAM:\n\tsym = addparm(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_MEMBER:\n\tsym = addmemb(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n    }\n  }\n  return (sym);\n}\n\n// var_declaration_list: <null>\n//           | variable_declaration\n//           | variable_declaration separate_token var_declaration_list ;\n//\n// When called to parse function parameters, separate_token is ','.\n// When called to parse members of a struct/union, separate_token is ';'.\n//\n// Parse a list of variables.\n// Add them as symbols to one of the symbol table lists, and return the\n// number of variables. If funcsym is not NULL, there is an existing function\n// prototype, so compare each variable's type against this prototype.\nstatic int var_declaration_list(struct symtable *funcsym, int class,\n\t\t\t\tint separate_token, int end_token) {\n  int type;\n  int paramcnt = 0;\n  struct symtable *protoptr = NULL;\n  struct symtable *ctype;\n\n  // If there is a prototype, get the pointer\n  // to the first prototype parameter\n  if (funcsym != NULL)\n    protoptr = funcsym->member;\n\n  // Loop until the final end token\n  while (Token.token != end_token) {\n    // Get the type and identifier\n    type = parse_type(&ctype, &class);\n    ident();\n\n    // Check that this type matches the prototype if there is one\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    } else {\n      // Add a new parameter to the right symbol table list, based on the class\n      var_declaration(type, ctype, class);\n    }\n    paramcnt++;\n\n    // Must have a separate_token or ')' at this point\n    if ((Token.token != separate_token) && (Token.token != end_token))\n      fatald(\"Unexpected token in parameter list\", Token.token);\n    if (Token.token == separate_token)\n      scan(&Token);\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((funcsym != NULL) && (paramcnt != funcsym->nelems))\n    fatals(\"Parameter count mismatch for function\", funcsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(Text)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym = addglob(Text, type, NULL, S_FUNCTION, C_GLOBAL, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = var_declaration_list(oldfuncsym, C_PARAM, T_COMMA, T_RPAREN);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel));\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  int offset;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text, P_STRUCT, NULL, 0, 0);\n  else\n    ctype = addunion(Text, P_UNION, NULL, 0, 0);\n  scan(&Token);\n\n  // Scan in the list of members and attach\n  // to the struct type's node\n  var_declaration_list(NULL, C_MEMBER, T_SEMI, T_RBRACE);\n  rbrace();\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->posn = genalign(m->type, offset, 1);\n    else\n      m->posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nint typedef_declaration(struct symtable **ctype) {\n  int type, class=0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0) \n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype, 0, 0);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nint type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  struct symtable *ctype;\n  int type, class= C_GLOBAL;\n\n  while (1) {\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n\n    // Get the type\n    type = parse_type(&ctype, &class);\n\n    // We might have just parsed a struct, union or enum\n    // declaration with no associated variable.\n    // The next token might be a ';'. Loop back if it is.\n    // XXX: I'm not happy with this as it allows\n    // \"struct fred;\" as an accepted statement\n    if (type == -1) {\n      semi();\n      continue;\n    }\n    // We have to read past the identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration\n      tree = function_declaration(type);\n\n      // Only a function prototype, no code\n      if (tree == NULL)\n\tcontinue;\n\n      // A real function, generate the assembly code for it\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, ctype, class);\n      semi();\n    }\n  }\n}\n"
  },
  {
    "path": "35_Preprocessor/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int reg, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint size, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int size);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addunion(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint parse_type(struct symtable **ctype, int *class);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "35_Preprocessor/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  union {\n    int size;\t\t\t// Number of elements in the symbol\n    int endlabel;\t\t// For functions, the end label\n  };\n  union {\n    int nelems;\t\t\t// For functions, # of params\n    int posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  };\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  union {\t\t\t// the symbol in the symbol table\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "35_Preprocessor/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "35_Preprocessor/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int label, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, NOLABEL, n->op);\n      genfreeregs();\n      genAST(n->right, NOLABEL, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, label));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, label));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "35_Preprocessor/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "35_Preprocessor/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "35_Preprocessor/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "35_Preprocessor/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "35_Preprocessor/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "35_Preprocessor/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t\t// Use the character put\n    c = Putback;\t\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t\t// Read from input file\n\n  while (c == '#') {\t\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n'); // Skip to the end of the line\n    c = fgetc(Infile);\t\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "35_Preprocessor/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  bodyAST = compound_statement();\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  bodyAST = compound_statement();\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type, class= C_LOCAL;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not do the default code in this switch statement.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL)\n        return (binexpr(0));\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration\n      // and skip over the semicolon\n      type = parse_type(&ctype, &class);\n      ident();\n      var_declaration(type, ctype, class);\n      semi();\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN ||\n\t\t\t tree->op == A_RETURN || tree->op == A_FUNCCALL))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "35_Preprocessor/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int size, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->size = size;\n  node->posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(node);\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, size, 0);\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, size, 0);\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, size, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, size, 0);\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_STRUCT, size, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_UNION, size, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_TYPEDEF, size, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:15 on line 5 of input31.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input32.c",
    "content": "Unknown variable:cow on line 4 of input32.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input33.c",
    "content": "Incompatible type to return on line 4 of input33.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input34.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input34.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 4 of input35.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input36.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input37.c",
    "content": "Unexpected token in parameter list:15 on line 3 of input37.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input38.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 4 of input39.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input40.c",
    "content": "No return for function with non-void type on line 4 of input40.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input41.c",
    "content": "Can't return from a void function on line 3 of input41.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input42.c",
    "content": "Undeclared function:fred on line 3 of input42.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input43.c",
    "content": "Undeclared array:b on line 3 of input43.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input44.c",
    "content": "Unknown variable:z on line 3 of input44.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 3 of input45.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input46.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 3 of input47.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 3 of input48.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 6 of input49.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 6 of input50.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input51.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 5 of input52.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input56.c",
    "content": "unknown struct/union type:var1 on line 2 of input56.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input57.c",
    "content": "previously defined struct/union:fred on line 2 of input57.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input59.c",
    "content": "Undeclared variable:y on line 3 of input59.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input60.c",
    "content": "Undeclared variable:x on line 3 of input60.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input61.c",
    "content": "Undeclared variable:x on line 3 of input61.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input64.c",
    "content": "undeclared enum type::fred on line 1 of input64.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input65.c",
    "content": "enum type redeclared::fred on line 2 of input65.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input66.c",
    "content": "enum value redeclared::z on line 2 of input66.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input68.c",
    "content": "redefinition of typedef:FOO on line 2 of input68.c\n"
  },
  {
    "path": "35_Preprocessor/tests/err.input69.c",
    "content": "unknown type:FLOO on line 2 of input69.c\n"
  },
  {
    "path": "35_Preprocessor/tests/input01.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input02.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input03.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input04.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input05.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input06.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input07.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input08.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input09.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input10.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input11.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input12.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input13.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input14.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input15.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input16.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input17.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input18.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input18a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input19.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input20.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input21.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input22.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input23.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input24.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input25.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input26.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input27.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input28.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input29.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input31.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input32.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input33.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input34.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input35.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input36.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "35_Preprocessor/tests/input37.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "35_Preprocessor/tests/input38.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "35_Preprocessor/tests/input39.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "35_Preprocessor/tests/input40.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "35_Preprocessor/tests/input41.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "35_Preprocessor/tests/input42.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "35_Preprocessor/tests/input43.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "35_Preprocessor/tests/input44.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "35_Preprocessor/tests/input45.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "35_Preprocessor/tests/input46.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "35_Preprocessor/tests/input47.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "35_Preprocessor/tests/input48.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "35_Preprocessor/tests/input49.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input50.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input51.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input52.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input55.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input56.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "35_Preprocessor/tests/input57.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "35_Preprocessor/tests/input58.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input59.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input60.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input61.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input62.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input63.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input64.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "35_Preprocessor/tests/input65.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "35_Preprocessor/tests/input66.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "35_Preprocessor/tests/input67.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/input68.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "35_Preprocessor/tests/input69.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "35_Preprocessor/tests/input70.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i ../lib/printint.c\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input55.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input58.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input62.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input63.c",
    "content": "25\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input67.c",
    "content": "5\n17\n"
  },
  {
    "path": "35_Preprocessor/tests/out.input70.c",
    "content": "56\n"
  },
  {
    "path": "35_Preprocessor/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "35_Preprocessor/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "35_Preprocessor/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "35_Preprocessor/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return ((type & 0xf) == 0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\t// XXX Fix soon\n    rsize = typesize(rtype, NULL);\t// XXX Fix soon\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "36_Break_Continue/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "36_Break_Continue/Readme.md",
    "content": "# Part 36: `break` and `continue`\n\nA while back, when I wrote another\n[simple compiler](https://github.com/DoctorWkt/h-compiler)\nfor a typeless language, I didn't use an abstract syntax tree.\nThis made it awkward to add the `break` and `continue` keywords to\nthe language.\n\nHere, we do have an AST tree for each function. This makes it much easier\nto implement `break` and `continue`. I'll outline the reasons for this below.\n\n## Adding the `break` and `continue`\n\nUnsurprisingly, we have two new tokens T_BREAK and T_CONTINUE, and the\nscanner code in `scan.c` recognises the `break` and `continue` keywords.\nAs always, browse the code to see how this is done.\n\n## New AST Node Types\n\nWe also have two new AST node types in `defs.h`: A_BREAK and A_CONTINUE.\nWhen we parse a `break` keyword, we can generate an A_BREAK AST leaf;\nditto an A_CONTINUE leaf for the `continue` keyword.\n\nThen, when we walk the AST to generate the assembly code, when we encounter\nan A_BREAK node, we need to generate an assembly jump to the label at the\nend of the loop that we are currently in. And for A_CONTINUE, we jump to\nthe label just before the loop condition is evaluated.\n\nNow, how do we know which loop we are in?\n\n## Tracking the Most Recent Loop\n\nLoops can be nested, and so there can be any number of loop labels\nin use at any point. This is what I found difficult when I\nwrote my previous compiler. Now that we have an AST which we traverse\nrecursively, we can pass the details of the latest loop's labels\ndown to our children in the AST tree.\n\nWe already do this sort of thing to get to the end of an 'if' or 'while'\nstatement. Here's some of the code for generating the assembly for 'if'\nfrom `gen.c`:\n\n```c\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, n->op);\n```\n\nThe left-hand AST child is the one that evaluates the 'if' statement's\ncondition, so it needs access to the label that we have just generated.\nSo when we generate this child's assembly output with `genAST()`, we\nalso pass in the label's details.\n\nFor loops, we need to pass to `genAST()` the label which is at the\nloop's end and also the label just before the code that evaluates the\nloop's condition. To this end, I've changed the interface to `genAST()`:\n\n```c\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\n```\n\nWe keep the existing `iflabel` and augment this with the two loop labels.\nNow we need to pass to `genAST()` the labels that are generated for each loop.\nSo, in the code to generate the 'while' loop code:\n\n```c\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  Lstart = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  ...\n}\n```\n\n## `genAST()` is Recursive\n\nNow, what about nested loops? Consider the code:\n\n```\nL1:\n  while (x < 10) {\n    if (x == 6) break;\nL2:\n    while (y < 10) {\n      if (y == 6) break;\n      y++;\n    }\nL3:\n    x++;\n  }\nL4:\n```\n\nthe `if (y == 6) break` should leave the inner loop and jump to the `x++`\ncode (i.e. L3), and the `if (x == 6) break;` code should leave the outer loop\nand jump to label L4.\n\nThis works because `genAST()` calls `genWHILE()` for the outer loop.\nThis calls `genAST(L1, L4)` so that the first `break` sees these loop\nlabels. Then, when we hit the second loop, `genWHILE()` is called again.\nIt generates new loop labels and calls `genAST(L2, L3)` to generate the\ninner loop code. Thus, the second `break` sees the L2 and L3 labels, not the\nL1 and L4 labels. \n\nFinally, once the inner compound statement is generated, the inside `genAST()`\nreturns, and get back to the code which sees L1 and L4 as the loop labels.\n\n## Implications of the Above\n\nWhat this means, in terms of implementation, is that anywhere that something\ncalls `genAST()` (including itself), and we could be in a loop, then the\ncurrent loop labels must get propagated down to the children involved.\n\nWe have already seen the change to `genWHILE()` to pass to `genAST()` the\nnew loop labels. Let's look at where else we need to propagate loop labels.\n\nWhen I first implemented `break`, I wrote this test program\n\n```c\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n```\n\nand generated the assembly for it. The `break` was being turned into\na jump to label L0, i.e. the loop's end label wasn't getting to the\ncode dealing with `break`. Looking at a stack trace for the compiler, I\nrealised that:\n\n  + The `genAST()` for the function called\n  + `genWHILE()` for the loop which generated the labels and passed them to\n  + `genAST()` for the loop body, which called\n  + `genIF()` which passed **no** labels in to\n  + `genAST()` for the 'if' body. Hence, the `break` never saw the labels.\n\nSo I also had to modify the argument list for `genIF()`:\n\n```c\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel);\n```\n\nI won't go through all the code in `gen.c`, but open up the file in\nan editor or text viewer and look for all the `genAST()` calls to see\nwhere the loop labels do get propagated.\n\nFinally, we actually do need to generate the assembly code for `break`\nand `continue`. Here is the code to do it in `genAST()` in `gen.c`:\n\n```c\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n```\n\n## Parsing `break` and `continue`\n\nThis time around I covered the code generation side before the parsing, but\nnow it's time to get to the parsing of these new keywords. Luckily the\nsyntax is either `break ;` or `continue ;`. So it would seem that they should\nbe easy to parse. There is, of course, a small wrinkle.\n\nWe parse individual statements in `single_statement()` in `stmt.c`, so\nthe change is small:\n\n```c\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n```\n\nwith a slight change in `compound_statement()` to ensure that the\nstatement is followed by a semicolon:\n\n```c\ncompound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  ...\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN || tree->op == A_RETURN\n                         || tree->op == A_FUNCCALL || tree->op == A_BREAK\n                         || tree->op == A_CONTINUE))\n      semi();\n    ...\n}\n```\n\nNow the wrinkle. This following program is not legal:\n\n```c\nint main() {\n  break;\n}\n```\n\nas there is no loop to break out of. We need to track the depth of\nthe loops we are parsing, and only allow a `break` or `continue` statement\nwhen the depth is not zero. Thus, the functions to parse these keywords\nlook like:\n\n```c\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to break out from\");\n  scan(&Token);\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n```\n\n## Loop Levels\n\nWe are going to need a `Looplevel` variable to track the level of the\nloops being parsed. This is in `data.h`:\n\n```c\nextern_ int Looplevel;                  // Depth of nested loops\n```\n\nWe need to set the level up as required. Each time we start a new\nfunction, the level is set to zero (in `decl.c`):\n\n```c\n// Parse the declaration of function.\nstruct ASTnode *function_declaration(int type) {\n  ...\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops yet\n  Looplevel= 0;\n  tree = compound_statement();\n  ...\n}\n```\n\nNow, each time we parse a loop, we increment the loop level for the\nloop's body (in `stmt.c`):\n\n```c\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  ...\n  // Get the AST for the compound statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = compound_statement();\n  Looplevel--;\n  ...\n}\n\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  ...\n  // Get the compound statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = compound_statement();\n  Looplevel--;\n  ...\n}\n```\n\nAnd this gives us the ability to determine if we are inside a loop or\nnot inside a loop.\n\n## The Test Code\n\nHere is the test code, `tests/input71.c`:\n\n```c\n#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n```\n\nAs I still haven't solved the \"dangling else\" problem, the `break`\nstatement has to enclosed in  '{' ... '}' to make it into a compound\nstatement. Apart from that, the code works as expected:\n\n```\n0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n```\n\n## Conclusion and What's Next\n\nI knew that adding support for `break` and `continue` was going to be\neasier than it was for my earlier compiler, because of the AST. However,\nthere were still some minor issues and wrinkles that we had to deal with\nin the process of implementing them.\n\nNow that we have the `break` keyword in the language, I will attempt to\nadd `switch` statements in the next part of our compiler writing journey.\nThis is going to require the addition of switch jump tables, and I know\nthis is going to be complicated. So get ready for an interesting next step. [Next step](../37_Switch/Readme.md)\n"
  },
  {
    "path": "36_Break_Continue/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch(type) {\n    case P_CHAR: return (offset);\n    case P_INT:\n    case P_LONG: break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment= 4;\n  offset = (offset + direction * (alignment-1)) & ~(alignment-1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      for (int i=0; i < size; i++)\n        fprintf(Outfile, \"\\t.byte\\t0\\n\");\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "36_Break_Continue/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "36_Break_Continue/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch(type) {\n    case P_CHAR: return (offset);\n    case P_INT:\n    case P_LONG: break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment= 4;\n  offset = (offset + direction * (alignment-1)) & ~(alignment-1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  // original version\n  for (int i = 0; i < node->size; i++) {\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(size) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", node->size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", node->size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", node->size);\n      break;\n    default:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "36_Break_Continue/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "36_Break_Continue/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic void enum_declaration(void);\nint typedef_declaration(struct symtable **ctype);\nint type_of_typedef(char *name, struct symtable **ctype);\n\n\n// Parse the current token and return a\n// primitive type enum value, a pointer\n// to any composite type and possibly\n// modify the class of the type.\n// Also scan in the next token.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic=1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN: *class= C_EXTERN; scan(&Token); break;\n      default: exstatic= 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type.\n// class is the variable's class\n// Return the pointer to variable's entry in the symbol table\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class) {\n  struct symtable *sym = NULL;\n\n  // See if this has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      if (findglob(Text) != NULL)\n\tfatals(\"Duplicate global variable declaration\", Text);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(Text) != NULL)\n\tfatals(\"Duplicate local variable declaration\", Text);\n    case C_MEMBER:\n      if (findmember(Text) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", Text);\n  }\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      switch (class) {\n\tcase C_EXTERN:\n\tcase C_GLOBAL:\n\t  sym =\n\t    addglob(Text, pointer_to(type), ctype, S_ARRAY, class, Token.intvalue);\n\t  break;\n\tcase C_LOCAL:\n\tcase C_PARAM:\n\tcase C_MEMBER:\n\t  fatal\n\t    (\"For now, declaration of non-global arrays is not implemented\");\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    switch (class) {\n      case C_EXTERN:\n      case C_GLOBAL:\n\tsym = addglob(Text, type, ctype, S_VARIABLE, class, 1);\n\tbreak;\n      case C_LOCAL:\n\tsym = addlocl(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_PARAM:\n\tsym = addparm(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_MEMBER:\n\tsym = addmemb(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n    }\n  }\n  return (sym);\n}\n\n// var_declaration_list: <null>\n//           | variable_declaration\n//           | variable_declaration separate_token var_declaration_list ;\n//\n// When called to parse function parameters, separate_token is ','.\n// When called to parse members of a struct/union, separate_token is ';'.\n//\n// Parse a list of variables.\n// Add them as symbols to one of the symbol table lists, and return the\n// number of variables. If funcsym is not NULL, there is an existing function\n// prototype, so compare each variable's type against this prototype.\nstatic int var_declaration_list(struct symtable *funcsym, int class,\n\t\t\t\tint separate_token, int end_token) {\n  int type;\n  int paramcnt = 0;\n  struct symtable *protoptr = NULL;\n  struct symtable *ctype;\n\n  // If there is a prototype, get the pointer\n  // to the first prototype parameter\n  if (funcsym != NULL)\n    protoptr = funcsym->member;\n\n  // Loop until the final end token\n  while (Token.token != end_token) {\n    // Get the type and identifier\n    type = parse_type(&ctype, &class);\n    ident();\n\n    // Check that this type matches the prototype if there is one\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    } else {\n      // Add a new parameter to the right symbol table list, based on the class\n      var_declaration(type, ctype, class);\n    }\n    paramcnt++;\n\n    // Must have a separate_token or ')' at this point\n    if ((Token.token != separate_token) && (Token.token != end_token))\n      fatald(\"Unexpected token in parameter list\", Token.token);\n    if (Token.token == separate_token)\n      scan(&Token);\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((funcsym != NULL) && (paramcnt != funcsym->nelems))\n    fatals(\"Parameter count mismatch for function\", funcsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(Text)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym = addglob(Text, type, NULL, S_FUNCTION, C_GLOBAL, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = var_declaration_list(oldfuncsym, C_PARAM, T_COMMA, T_RPAREN);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops yet\n  Looplevel= 0;\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel));\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  int offset;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text, P_STRUCT, NULL, 0, 0);\n  else\n    ctype = addunion(Text, P_UNION, NULL, 0, 0);\n  scan(&Token);\n\n  // Scan in the list of members and attach\n  // to the struct type's node\n  var_declaration_list(NULL, C_MEMBER, T_SEMI, T_RBRACE);\n  rbrace();\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->posn = genalign(m->type, offset, 1);\n    else\n      m->posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nint typedef_declaration(struct symtable **ctype) {\n  int type, class=0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0) \n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype, 0, 0);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nint type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  struct symtable *ctype;\n  int type, class= C_GLOBAL;\n\n  while (1) {\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n\n    // Get the type\n    type = parse_type(&ctype, &class);\n\n    // We might have just parsed a struct, union or enum\n    // declaration with no associated variable.\n    // The next token might be a ';'. Loop back if it is.\n    // XXX: I'm not happy with this as it allows\n    // \"struct fred;\" as an accepted statement\n    if (type == -1) {\n      semi();\n      continue;\n    }\n    // We have to read past the identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration\n      tree = function_declaration(type);\n\n      // Only a function prototype, no code\n      if (tree == NULL)\n\tcontinue;\n\n      // A real function, generate the assembly code for it\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, ctype, class);\n      semi();\n    }\n  }\n}\n"
  },
  {
    "path": "36_Break_Continue/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint size, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int size);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addunion(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint parse_type(struct symtable **ctype, int *class);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "36_Break_Continue/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  union {\n    int size;\t\t\t// Number of elements in the symbol\n    int endlabel;\t\t// For functions, the end label\n  };\n  union {\n    int nelems;\t\t\t// For functions, # of params\n    int posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  };\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  union {\t\t\t// the symbol in the symbol table\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "36_Break_Continue/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "36_Break_Continue/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "36_Break_Continue/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "36_Break_Continue/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "36_Break_Continue/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "36_Break_Continue/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "36_Break_Continue/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "36_Break_Continue/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t\t// Use the character put\n    c = Putback;\t\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t\t// Read from input file\n\n  while (c == '#') {\t\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n'); // Skip to the end of the line\n    c = fgetc(Infile);\t\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "36_Break_Continue/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = compound_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = compound_statement();\n  Looplevel--;\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to break out from\");\n  scan(&Token);\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type, class = C_LOCAL;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not do the default code in this switch statement.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL)\n\treturn (binexpr(0));\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration\n      // and skip over the semicolon\n      type = parse_type(&ctype, &class);\n      ident();\n      var_declaration(type, ctype, class);\n      semi();\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN || tree->op == A_RETURN\n\t\t\t || tree->op == A_FUNCCALL || tree->op == A_BREAK\n\t\t\t || tree->op == A_CONTINUE))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "36_Break_Continue/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int size, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->size = size;\n  node->posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(node);\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, size, 0);\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, size, 0);\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, size, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, size, 0);\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_STRUCT, size, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_UNION, size, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_TYPEDEF, size, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:15 on line 5 of input31.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input32.c",
    "content": "Unknown variable:cow on line 4 of input32.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input33.c",
    "content": "Incompatible type to return on line 4 of input33.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input34.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input34.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 4 of input35.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input36.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input37.c",
    "content": "Unexpected token in parameter list:15 on line 3 of input37.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input38.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 4 of input39.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input40.c",
    "content": "No return for function with non-void type on line 4 of input40.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input41.c",
    "content": "Can't return from a void function on line 3 of input41.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input42.c",
    "content": "Undeclared function:fred on line 3 of input42.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input43.c",
    "content": "Undeclared array:b on line 3 of input43.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input44.c",
    "content": "Unknown variable:z on line 3 of input44.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 3 of input45.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input46.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 3 of input47.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 3 of input48.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 6 of input49.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 6 of input50.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input51.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 5 of input52.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input56.c",
    "content": "unknown struct/union type:var1 on line 2 of input56.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input57.c",
    "content": "previously defined struct/union:fred on line 2 of input57.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input59.c",
    "content": "Undeclared variable:y on line 3 of input59.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input60.c",
    "content": "Undeclared variable:x on line 3 of input60.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input61.c",
    "content": "Undeclared variable:x on line 3 of input61.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input64.c",
    "content": "undeclared enum type::fred on line 1 of input64.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input65.c",
    "content": "enum type redeclared::fred on line 2 of input65.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input66.c",
    "content": "enum value redeclared::z on line 2 of input66.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input68.c",
    "content": "redefinition of typedef:FOO on line 2 of input68.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input69.c",
    "content": "unknown type:FLOO on line 2 of input69.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input72.c",
    "content": "no loop to break out from on line 1 of input72.c\n"
  },
  {
    "path": "36_Break_Continue/tests/err.input73.c",
    "content": "no loop to continue to on line 1 of input73.c\n"
  },
  {
    "path": "36_Break_Continue/tests/input01.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input02.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input03.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input04.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input05.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input06.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input07.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input08.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input09.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input10.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input11.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input12.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input13.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input14.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input15.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input16.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input17.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input18.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input18a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input19.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input20.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input21.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input22.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input23.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input24.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input25.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input26.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input27.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input28.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input29.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input31.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input32.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input33.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input34.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input35.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input36.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "36_Break_Continue/tests/input37.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "36_Break_Continue/tests/input38.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "36_Break_Continue/tests/input39.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "36_Break_Continue/tests/input40.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "36_Break_Continue/tests/input41.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "36_Break_Continue/tests/input42.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "36_Break_Continue/tests/input43.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "36_Break_Continue/tests/input44.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "36_Break_Continue/tests/input45.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "36_Break_Continue/tests/input46.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "36_Break_Continue/tests/input47.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "36_Break_Continue/tests/input48.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "36_Break_Continue/tests/input49.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input50.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input51.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input52.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input55.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input56.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "36_Break_Continue/tests/input57.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "36_Break_Continue/tests/input58.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input59.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input60.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input61.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input62.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input63.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input64.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "36_Break_Continue/tests/input65.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "36_Break_Continue/tests/input66.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "36_Break_Continue/tests/input67.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input68.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "36_Break_Continue/tests/input69.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "36_Break_Continue/tests/input70.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input71.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue;\n    }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/input72.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "36_Break_Continue/tests/input73.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "36_Break_Continue/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i ../lib/printint.c\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input55.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input58.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input62.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input63.c",
    "content": "25\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input67.c",
    "content": "5\n17\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input70.c",
    "content": "56\n"
  },
  {
    "path": "36_Break_Continue/tests/out.input71.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "36_Break_Continue/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "36_Break_Continue/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "36_Break_Continue/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "36_Break_Continue/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return ((type & 0xf) == 0);\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\t// XXX Fix soon\n    rsize = typesize(rtype, NULL);\t// XXX Fix soon\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "37_Switch/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "37_Switch/Readme.md",
    "content": "# Part 37: Switch Statements\n\nIn this part of our compiler writing journey, we are going to implement\nthe 'switch' statement. This is really tricky for several reasons which\nI'll cover. So let's start with an example and look at the implications.\n\n## An Example Switch Statement\n\n```c\n  switch(x) {\n    case 1:  printf(\"One\\n\");  break;\n    case 2:  printf(\"Two\\n\");  break;\n    case 3:  printf(\"Three\\n\");\n    default: printf(\"More than two\\n\");\n  }\n```\n\nThis is like a multi-way 'if' statement where the value of `x` chooses\nthe branch to take. However, we need to insert the `break` statement to\nbypass all the other branches; if we leave out the `break` statement,\nthe branch that we are in falls through and continues on with the execution\nof the next branch.\n\nThe expression for the 'switch' decision has to be integer, and all of the\ncase options have to be integer literals. We can't say `case 3*y+17`, for\nexample.\n\nThe `default` case catches all values that are not given by previous cases.\nIt has to appear as the last case in the list. Also, we cannot have duplicate\ncase values, so `case 2: ...; case 2` is not permitted.\n\n## Converting the Above into Assembly\n\nOne way to translate a 'switch' statement into assembly is to treat it\nas a multi-way 'if' statement. This would mean that we would compare\n`x` against integer values, one after the other, and go into or skip\nover sections of assembly code as required. This would work but it makes\nthe assembly code inefficient, especially if you consider this example:\n\n```c\n  switch (2 * x - (18 +y)/z) { ... }\n```\n\nGiven our current\n\"[KISS](https://en.wikipedia.org/wiki/KISS_principle)\"\ncompiler's operation, we would have to evaluate the\nexpression again and again for each comparison against a literal value.\n\nIt makes more sense to evaluate the 'switch' expression once. Then, compare\nthis value against a table of case literal values. When we find a match, we\njump to the code branch associated with the case values. This is known\nas a [jump table](https://en.wikipedia.org/wiki/Branch_table).\n\nIt means that, for each case option, we will need to create a label to place\nat the beginning of the code for this option. As an example, the jump table\nfor the first example above might look like:\n\n| Case Value | Label |\n|:----------:|:-----:|\n|     1      |  L18  |\n|     2      |  L19  |\n|     3      |  L22  |\n|  default   |  L26  |\n\nWe also need a label to mark the code after the 'switch' statement. When\none code branch wants to `break;`, we jump to this 'switch' end label.\nOtherwise, we let the code branch fall through into the next code branch.\n\n## Parsing Implications\n\nAll of the above is fine and good, except that we have to parse a 'switch'\nstatement from top to bottom. This means that we won't know how big the\njump table should be until after we have parsed all of the cases. This\nalso means that, unless we perform some clever tricks, we will have generated\nthe assembly code for all the cases *before* we can generate the jump table.\n\nAs you know, I'm writing this compiler following the \"KISS principle\": keep\nit simple, stupid! So I am avoiding the clever tricks, but this means that,\nyes, we are going to delay the output of the jump table until after we\ngenerate all of the assembly code for the various cases.\n\nVisually, here is how we are going to lay out our code:\n\n![](Figs/switch_logic.png)\n\nThe code to evaluate the switch decision is at the top, as we parse it first.\nWe don't want to continue on into the first case, so we can jump to a label\nwhich we will output later.\n\nThen we parse each case statement and generate the corresponding assembly code.\nWe will have already generated an \"end of switch\" label, so we can jump to it.\nAgain, we will output this label later.\n\nAs we generate each case, we get a label for it and output this label. \nOnce all the cases and the default case (if any) are output, we can now\ngenerate the jump table.\n\nBut now we need some code to walk the jump table, compare the switch\ndecision against each case value, and jump appropriately. We could\ngenerate this assembly code for each and every 'switch' statement but,\nif this jump handling code is large, we will be wasting memory. It's\nbetter to have one copy of the jump handling code in memory, but now\nwe have to jump to it! Even worse, this code doesn't know which register\nholds the switch decision result, so we will have to copy this register\ninto a known register, and copy the base of the jump table into a known\nregister.\n\nWhat we have done here is trade off complexity in the parsing and code\ngeneration for a spaghetti of assembly code with jumps all over the place.\nWell, the CPU can deal with the jump spaghetti, so for now it's a fair\ntradeoff. Obviously, a production compiler would do things differently.\n\nThe red lines in the diagram show the flow of execution from the\nswitch decision to loading the registers to the jump table handling\nand finally to the specific case code. The green line shows that the\nbase address of the jump table is passed to the jump table handling code.\nFinally, the blue lines shows that the case ended with a `break;` which\njumped to the end of the switch assembly code.\n\nSo, the assembly output is ugly but it does work. Now that we've seen\nhow we are going to implement 'switch' statements, let's actually do it.\n\n## New Keywords and Tokens\n\nWe have two new tokens, T_CASE and T_DEFAULT, to go along with the new `case`\nand `default` keywords. As always, browse the code to see how this is done.\n\n## New AST Node Types\n\nWe need to build the AST tree to represent 'switch' statements. The structure\nof a 'switch' statement is in no way a binary tree like our expressions.\nBut it is *our* AST tree, so we can shape it any way that suits us.\nSo I sat down for a bit and decided to go with this structure:\n\n![](Figs/switch_ast.png)\n\nThe root of the 'switch' tree is A_SWITCH, On the left is the sub-tree with\nthe expression that calculates the switch's condition. On the right we\nhave a linked list of A_CASE nodes, one for each case. Finally, there is\nan optional A_DEFAULT to capture any default case.\n\nThe `intvalue` field in each A_CASE node will hold the case value which\nthe expression must match. The left child sub-tree will hold the details\nof the compound statement which is the case's body. At this point, we don't\nhave any jump labels or the jump table: we will generate this later.\n\n## Parsing the Switch Statement\n\nWith all the above on-board, we're now ready to look at the parsing of\na 'switch' statement. There is quite a lot of error checking code here,\nso I will take it in small sections. This code is in `stmt.c` and\nis called from `single_statement()`:\n\n```c\n    case T_SWITCH:\n      return (switch_statement());\n```\n\nLet's go..\n\n```c\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n```\n\nOK, so there's a lot of local variables at the top which should clue you\nin that we will have to deal with some state in this function. This first\nsection is easy, though: parse the `switch (expression) {` syntax, \nget the AST for the expression and ensure that its is of integer type.\n\n```c\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n```\n\nWe've got the switch decision tree, so we can now build the A_SWITCH node\nwhich we will return. Do you remember that we could only let a `break;`\noccur when we are inside at least one loop. Well, now we also have to\nlet `break;` happen when there is at least one 'switch' statement. Thus,\nthere is a new global variable, `Switchlevel` to record this.\n\n```c\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n                        fatal(\"No cases in switch\");\n                     inloop=0; break;\n  ...\n  }\n```\n\nThe loop is controlled by `inloop` which starts at one. When we hit a '}'\ntoken, we reset it to zero and break out of this 'switch' statement, thus\nending the loop. We also check that we have seen at least one case.\n\n> It's a bit weird using a 'switch' statement to parse 'switch' statements.\n\nNow we move on to the parsing of `case` and `default`:\n\n```c\n      case T_CASE:\n      case T_DEFAULT:\n        // Ensure this isn't after a previous 'default'\n        if (seendefault)\n          fatal(\"case or default after existing default\");\n```\n\nWe have a lot of common code to perform, so both tokens fall into the\nsame code. First, ensure that we haven't already seen a default case,\nand this has to be the last case in the series.\n\n```c\n        // Set the AST operation. Scan the case value if required\n        if (Token.token==T_DEFAULT) {\n          ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n        } else ...\n```\n\nIf we are parsing `default:`, then there is no following integer value.\nSkip over the keyword and record that we have seen a default case.\n\n```c\n        } else  {\n          ASTop= A_CASE; scan(&Token);\n          left= binexpr(0);\n          // Ensure the case value is an integer literal\n          if (left->op != A_INTLIT)\n            fatal(\"Expecting integer literal for case value\");\n          casevalue= left->intvalue;\n\n          // Walk the list of existing case values to ensure\n          // that there isn't a duplicate case value\n          for (c= casetree; c != NULL; c= c -> right)\n            if (casevalue == c->intvalue)\n              fatal(\"Duplicate case value\");\n        }\n```\n\nThis code deals specifically with `case <value>:`. We read in the value after\nthe case using `binexpr()`. Now, I could have been \"clever\" and called\n`primary()` instead  which goes straight to parsing integer literals.\nHowever, `primary()` can call `binexpr()` anyway, so it really doesn't make\nany difference: we are still going to have to error check the resulting\ntree to ensure that it is an A_INTLIT node only.\n\nThen we walk the list of previous A_CASE nodes that we have (`casetree`\npoints to the head of this list) to ensure that we don't have any\nduplicate case values.\n\nAlong the way, we have set the `ASTop` variable to either A_CASE for\na case with an integer literal value or A_DEFAULT for the default case.\nWe can now perform the code common to both.\n\n```c\n        // Scan the ':' and get the compound expression\n        match(T_COLON, \":\");\n        left= compound_statement(); casecount++;\n\n        // Build a sub-tree with the compound statement as the left child\n        // and link it in to the growing A_CASE tree\n        if (casetree==NULL) {\n          casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n        } else {\n          casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n          casetail= casetail->right;\n        }\n        break;\n```\n\nCheck that the next token is a ':'. Get the AST sub-tree with the\ncompound statement in it. Build an A_CASE or A_DEFAULT node with\nthis sub-tree as the left child, and link this to the linked list\nof A_CASE/A_DEFAULT nodes: `casetree` is the head and `casetail`\nis the tail of this list.\n\n```c\n      default:\n        fatald(\"Unexpected token in switch\", Token.token);\n    }\n  }\n```\n\nThere should only be `case` and `default` keywords in the 'switch' body,\nso ensure that this is the case.\n\n```c\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n```\n\nWe've finally parsed all of the cases and the default case, and we now\nhave the count of them and the list which `casetree` points to. Add\nthese values to the A_SWITCH node and return this as the final tree.\n\nOK, so that was a substantial amount of parsing. Now we need to\nturn our attention to code generation.\n\n## Switch Code Generation: An Example.\n\nAt this point I think it would be worth seeing the assembly output of\nan example 'switch' statement so that you can see how the code matches\nthe graphic of execution flow that I gave at the top. Here is the example:\n\n```c\n#include <stdio.h>\n\nint x; int y;\n\nint main() {\n  switch(x) {\n    case 1:  { y= 5; break; }\n    case 2:  { y= 7; break; }\n    case 3:  { y= 9; }\n    default: { y= 100; }\n  }\n  return(0);\n}\n```\n\nFirst up, yes we do need '{' ... '}' around the case bodies. This is\nbecause I still haven't solved the \"dangling else\" problem, so all\ncompound statements have to be surrounded by '{' ... '}'.\n\nI'm going to leave out the jump table handling code for now, but here is\nthe assembly output for this example:\n\n![](Figs/switch_logic2.png)\n\nThe code that loads `x` into a register is at the top, and it\njumps down past the jump table. As the jump table handling code\ndoesn't know which register this will be, we always load the\nvalue into `%rax`, and we load the jump table's base address\ninto `%rdx`.\n\nThe jump table itself has this structure:\n\n + First is the number of cases with integer values\n + Next is a set of value/label pairs, one for each case\n + Finally there is the label of the default case. If there is\n   no default case, this has to be the label of the 'switch' end,\n   so that we do no code if there is no matching case.\n\nThe jump table handling code (which we will look at soon)\ninterprets the jump table and jumps to one of the labels in this\ntable. Let's assume that we have jumped to `L11` which is \n`case 2:`. We perform the code for this case option. This option\nhas  a `break;` statement, so there is a jump to `L9` which is\nthe label for the end of the 'switch' statement.\n\n## The Jump Table Handling Code\n\nYou already know that x86-64 assembly code isn't my forte.\nTherefore, I've borrowed the jump table handling code directly\nfrom [SubC](http://www.t3x.org/subc/). I've added it to\nthe `cgpreamble()` function in `cg.c`, so that it is output\nfor every assembly file that we create. Here is the commented code:\n\n```\n# internal switch(expr) routine\n# %rsi = switch table, %rax = expr\n\nswitch:\n        pushq   %rsi            # Save %rsi\n        movq    %rdx,%rsi       # Base of jump table -> %rsi\n        movq    %rax,%rbx       # Switch value -> %rbx\n        cld                     # Clear direction flag\n        lodsq                   # Load count of cases into %rcx,\n        movq    %rax,%rcx       # incrementing %rsi in the process\nnext:\n        lodsq                   # Get the case value into %rdx\n        movq    %rax,%rdx\n        lodsq                   # and the label address into %rax\n        cmpq    %rdx,%rbx       # Does switch value matches the case?\n        jnz     no              # No, jump over this code\n        popq    %rsi            # Restore %rsi\n        jmp     *%rax           # and jump to the chosen case\nno:\n        loop    next            # Loop for the number of cases\n        lodsq                   # Out of loop, load default label address\n        popq    %rsi            # Restore %rsi\n        jmp     *%rax           # and jump to the default case\n```\n\nWe need to thanks Nils Holm for writing this, as I would never have arrived\nat this code!\n\nNow we can look at how the above assembly code\ngets generated. Fortunately, we already have lots\nof useful functions in `cg.c` which we can reuse.\n\n## Generating the Assembly Code\n\nIn `genAST()` in `gen.c`, up near the top we identify an A_SWITCH\nnode and call a function to deal with this node and the tree below it.\n\n```c\n    case A_SWITCH:\n      return (genSWITCH(n));\n```\n\nSo let's look at this new function in stages:\n\n```c\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->intvalue + 1) * sizeof(int));\n```\n\nThe reason for the `+1` here is that we may have a default\ncase which needs a label even though it doesn't have a\ncase value.\n\n```c\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n```\n\nThese labels are made but not output as assembly yet.\nUntil we have a default label, we set it to `Lend`.\n\n```c\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs();\n```\n\nWe output the code to jump to the code after the\njump table even though it hasn't been output. We can\nalso free all the registers at this point.\n\n```c\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs();\n  }\n```\n\nThis is the code that both generates the label for each case\nand also outputs the assembly code which is the body of the\ncase. We store the case value and the case label in the two\narrays. And, if this is the default case, we can update\n`defaultlabel` with the correct label.\n\nAlso note that `genAST()` gets passed `Lend` which is the\nlabel after our 'switch' code. This allows any `break;`\nin the case body to jump out to what comes next.\n\n```c\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n```\n\nWe can't rely on the programmer to end their last case\nwith a `break;'` statement, so we force the last case to\nhave a jump to the end of the switch statement.\n\nAt this point we have:\n\n + the register which has the switch value\n + the array of case values\n + the array of case labels\n + the number of cases\n + some useful labels\n\nWe pass all of these into `cgswitch()` in `cg.c`,\nand (apart from the code from SubC) this is the only new\nassembly code we need to introduce for this part.\n\n## `cgswitch()`\n\nHere, we need to build the jump table and\nload the registers so that we can jump to\nthe `switch` assembly code. As a reminder,\nhere is the jump table structure:\n\n + First is the number of cases with integer values\n + Next is a set of value/label pairs, one for each case\n + Finally there is the label of the default case. If there is\n   no default case, this has to be the label of the 'switch' end,\n   so that we do no code if there is no matching case.\n\nFor our example, the jump table looks like:\n\n```\nL14:                                    # Switch jump table\n        .quad   3                       # Three case values\n        .quad   1, L10                  # case 1: jump to L10\n        .quad   2, L11                  # case 2: jump to L11\n        .quad   3, L12                  # case 3: jump to L12\n        .quad   L13                     # default: jump to L13\n```\n\nHere is how we generate all of this.\n\n\n```c\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n              int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n```\n\nThis is the `L14:` above.\n\n```c\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n```\n\nWe must have at least one case value/label\npair in the jump table. This code makes one\nthat points at the default case. The case\nvalue is irrelevant: if it matches, fine. If\nnot, we jump to the default case anyway.\n\n```c\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n```\n\nHere is the code to generate the jump table. Nice and easy.\n\n```c\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n```\n\nFinally, load the `%rax` register with the switch\nvalue, load `%rdx` with the label of the jump table\nand call the `switch` code.\n\n## Testing The Code\n\nI've augmented our example with a loop so that all\ncases in the 'switch' statement get tested This is\nthe file `tests/input74.c`:\n\n```c\n#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n```\n\nAnd here is the output from the program:\n\n```\n100\n5\n7\n100\n100\n```\n\nNote that the value 9 is not output, because we\nfall into the default case when we are doing case 3.\n\n## Conclusion and What's Next\n\nWe've just implemented our first really big new statement in\nour compiler, the 'switch' statement. As I've never done this\nbefore, I essentially followed the SubC implementation. There\nare many other, more efficient, ways to implement 'switch',\nbut I applied the \"KISS principle\" here. That said, it still\nwas quite a complicated implementation.\n\nIf you are still reading at this point, congratulations on\nyour staying power!\n\nI'm starting to get annoyed with the compulsory '{' ... '}'\naround all of our compound statements.\nSo, in the next part of our compiler writing journey, \nI will bite the bullet and attempt to solve the \"dangling else\"\nproblem. [Next step](../38_Dangling_Else/Readme.md)\n"
  },
  {
    "path": "37_Switch/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      for (int i = 0; i < size; i++)\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "37_Switch/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "37_Switch/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  // original version\n  for (int i = 0; i < node->size; i++) {\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(size) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", node->size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", node->size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", node->size);\n      break;\n    default:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "37_Switch/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "37_Switch/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic void enum_declaration(void);\nint typedef_declaration(struct symtable **ctype);\nint type_of_typedef(char *name, struct symtable **ctype);\n\n\n// Parse the current token and return a\n// primitive type enum value, a pointer\n// to any composite type and possibly\n// modify the class of the type.\n// Also scan in the next token.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic=1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN: *class= C_EXTERN; scan(&Token); break;\n      default: exstatic= 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatald(\"Illegal type, token\", Token.token);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type.\n// class is the variable's class\n// Return the pointer to variable's entry in the symbol table\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class) {\n  struct symtable *sym = NULL;\n\n  // See if this has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      if (findglob(Text) != NULL)\n\tfatals(\"Duplicate global variable declaration\", Text);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(Text) != NULL)\n\tfatals(\"Duplicate local variable declaration\", Text);\n    case C_MEMBER:\n      if (findmember(Text) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", Text);\n  }\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      switch (class) {\n\tcase C_EXTERN:\n\tcase C_GLOBAL:\n\t  sym =\n\t    addglob(Text, pointer_to(type), ctype, S_ARRAY, class, Token.intvalue);\n\t  break;\n\tcase C_LOCAL:\n\tcase C_PARAM:\n\tcase C_MEMBER:\n\t  fatal\n\t    (\"For now, declaration of non-global arrays is not implemented\");\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    switch (class) {\n      case C_EXTERN:\n      case C_GLOBAL:\n\tsym = addglob(Text, type, ctype, S_VARIABLE, class, 1);\n\tbreak;\n      case C_LOCAL:\n\tsym = addlocl(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_PARAM:\n\tsym = addparm(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_MEMBER:\n\tsym = addmemb(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n    }\n  }\n  return (sym);\n}\n\n// var_declaration_list: <null>\n//           | variable_declaration\n//           | variable_declaration separate_token var_declaration_list ;\n//\n// When called to parse function parameters, separate_token is ','.\n// When called to parse members of a struct/union, separate_token is ';'.\n//\n// Parse a list of variables.\n// Add them as symbols to one of the symbol table lists, and return the\n// number of variables. If funcsym is not NULL, there is an existing function\n// prototype, so compare each variable's type against this prototype.\nstatic int var_declaration_list(struct symtable *funcsym, int class,\n\t\t\t\tint separate_token, int end_token) {\n  int type;\n  int paramcnt = 0;\n  struct symtable *protoptr = NULL;\n  struct symtable *ctype;\n\n  // If there is a prototype, get the pointer\n  // to the first prototype parameter\n  if (funcsym != NULL)\n    protoptr = funcsym->member;\n\n  // Loop until the final end token\n  while (Token.token != end_token) {\n    // Get the type and identifier\n    type = parse_type(&ctype, &class);\n    ident();\n\n    // Check that this type matches the prototype if there is one\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    } else {\n      // Add a new parameter to the right symbol table list, based on the class\n      var_declaration(type, ctype, class);\n    }\n    paramcnt++;\n\n    // Must have a separate_token or ')' at this point\n    if ((Token.token != separate_token) && (Token.token != end_token))\n      fatald(\"Unexpected token in parameter list\", Token.token);\n    if (Token.token == separate_token)\n      scan(&Token);\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((funcsym != NULL) && (paramcnt != funcsym->nelems))\n    fatals(\"Parameter count mismatch for function\", funcsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(Text)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym = addglob(Text, type, NULL, S_FUNCTION, C_GLOBAL, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = var_declaration_list(oldfuncsym, C_PARAM, T_COMMA, T_RPAREN);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel= 0;\n  Switchlevel= 0;\n  tree = compound_statement();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel));\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  int offset;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text, P_STRUCT, NULL, 0, 0);\n  else\n    ctype = addunion(Text, P_UNION, NULL, 0, 0);\n  scan(&Token);\n\n  // Scan in the list of members and attach\n  // to the struct type's node\n  var_declaration_list(NULL, C_MEMBER, T_SEMI, T_RBRACE);\n  rbrace();\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->posn = genalign(m->type, offset, 1);\n    else\n      m->posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nint typedef_declaration(struct symtable **ctype) {\n  int type, class=0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0) \n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype, 0, 0);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nint type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  struct symtable *ctype;\n  int type, class= C_GLOBAL;\n\n  while (1) {\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n\n    // Get the type\n    type = parse_type(&ctype, &class);\n\n    // We might have just parsed a struct, union or enum\n    // declaration with no associated variable.\n    // The next token might be a ';'. Loop back if it is.\n    // XXX: I'm not happy with this as it allows\n    // \"struct fred;\" as an accepted statement\n    if (type == -1) {\n      semi();\n      continue;\n    }\n    // We have to read past the identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration\n      tree = function_declaration(type);\n\n      // Only a function prototype, no code\n      if (tree == NULL)\n\tcontinue;\n\n      // A real function, generate the assembly code for it\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, ctype, class);\n      semi();\n    }\n  }\n}\n"
  },
  {
    "path": "37_Switch/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\n\n// expr.c\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(void);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint size, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int size);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addunion(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint parse_type(struct symtable **ctype, int *class);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "37_Switch/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  union {\n    int size;\t\t\t// Number of elements in the symbol\n    int endlabel;\t\t// For functions, the end label\n  };\n  union {\n    int nelems;\t\t\t// For functions, # of params\n    int posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  };\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  union {\t\t\t// the symbol in the symbol table\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "37_Switch/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstatic struct ASTnode *expression_list(void) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the final right parentheses\n  while (Token.token != T_RPAREN) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Must have a ',' or ')' at this point\n    switch (Token.token) {\n    case T_COMMA:\n      scan(&Token);\n      break;\n    case T_RPAREN:\n      break;\n    default:\n      fatald(\"Unexpected token in expression list\", Token.token);\n    }\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list();\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatald(\"Expecting a primary expression, got token\", Token.token);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n        tokentype == T_COLON) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "37_Switch/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs();\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs();\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "37_Switch/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "37_Switch/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "37_Switch/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "37_Switch/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "37_Switch/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "37_Switch/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t\t// Use the character put\n    c = Putback;\t\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t\t// Read from input file\n\n  while (c == '#') {\t\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n'); // Skip to the end of the line\n    c = fgetc(Infile);\t\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n"
  },
  {
    "path": "37_Switch/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' compound_statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement\n  trueAST = compound_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the compound statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = compound_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' compound_statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the compound statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = compound_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' preop_statement ';'\n//                          true_false_expression ';'\n//                          postop_statement ')' compound_statement  ;\n//\n// preop_statement:  statement          (for now)\n// postop_statement: statement          (for now)\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op statement and the ';'\n  preopAST = single_statement();\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op statement and the ')'\n  postopAST = single_statement();\n  rparen();\n\n  // Get the compound statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = compound_statement();\n  Looplevel--;\n\n  // For now, all four sub-trees have to be non-NULL.\n  // Later on, we'll change the semantics for when some are missing\n\n  // Glue the compound statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and get the compound expression\n\tmatch(T_COLON, \":\");\n\tleft= compound_statement(); casecount++;\n\n\t// Build a sub-tree with the compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatald(\"Unexpected token in switch\", Token.token);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST\nstatic struct ASTnode *single_statement(void) {\n  int type, class = C_LOCAL;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not do the default code in this switch statement.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL)\n\treturn (binexpr(0));\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration\n      // and skip over the semicolon\n      type = parse_type(&ctype, &class);\n      ident();\n      var_declaration(type, ctype, class);\n      semi();\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      return (binexpr(0));\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST\nstruct ASTnode *compound_statement(void) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  // Require a left curly bracket\n  lbrace();\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // Some statements must be followed by a semicolon\n    if (tree != NULL && (tree->op == A_ASSIGN || tree->op == A_RETURN\n\t\t\t || tree->op == A_FUNCCALL || tree->op == A_BREAK\n\t\t\t || tree->op == A_CONTINUE))\n      semi();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n    // When we hit a right curly bracket,\n    // skip past it and return the AST\n    if (Token.token == T_RBRACE) {\n      rbrace();\n      return (left);\n    }\n  }\n}\n"
  },
  {
    "path": "37_Switch/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int size, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->size = size;\n  node->posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(node);\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, size, 0);\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, size, 0);\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, size, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, size, 0);\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_STRUCT, size, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_UNION, size, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_TYPEDEF, size, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "37_Switch/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:15 on line 5 of input31.c\n"
  },
  {
    "path": "37_Switch/tests/err.input32.c",
    "content": "Unknown variable:cow on line 4 of input32.c\n"
  },
  {
    "path": "37_Switch/tests/err.input33.c",
    "content": "Incompatible type to return on line 4 of input33.c\n"
  },
  {
    "path": "37_Switch/tests/err.input34.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input34.c\n"
  },
  {
    "path": "37_Switch/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 4 of input35.c\n"
  },
  {
    "path": "37_Switch/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input36.c\n"
  },
  {
    "path": "37_Switch/tests/err.input37.c",
    "content": "Unexpected token in parameter list:15 on line 3 of input37.c\n"
  },
  {
    "path": "37_Switch/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input38.c\n"
  },
  {
    "path": "37_Switch/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 4 of input39.c\n"
  },
  {
    "path": "37_Switch/tests/err.input40.c",
    "content": "No return for function with non-void type on line 4 of input40.c\n"
  },
  {
    "path": "37_Switch/tests/err.input41.c",
    "content": "Can't return from a void function on line 3 of input41.c\n"
  },
  {
    "path": "37_Switch/tests/err.input42.c",
    "content": "Undeclared function:fred on line 3 of input42.c\n"
  },
  {
    "path": "37_Switch/tests/err.input43.c",
    "content": "Undeclared array:b on line 3 of input43.c\n"
  },
  {
    "path": "37_Switch/tests/err.input44.c",
    "content": "Unknown variable:z on line 3 of input44.c\n"
  },
  {
    "path": "37_Switch/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 3 of input45.c\n"
  },
  {
    "path": "37_Switch/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input46.c\n"
  },
  {
    "path": "37_Switch/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 3 of input47.c\n"
  },
  {
    "path": "37_Switch/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 3 of input48.c\n"
  },
  {
    "path": "37_Switch/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 6 of input49.c\n"
  },
  {
    "path": "37_Switch/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 6 of input50.c\n"
  },
  {
    "path": "37_Switch/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input51.c\n"
  },
  {
    "path": "37_Switch/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 5 of input52.c\n"
  },
  {
    "path": "37_Switch/tests/err.input56.c",
    "content": "unknown struct/union type:var1 on line 2 of input56.c\n"
  },
  {
    "path": "37_Switch/tests/err.input57.c",
    "content": "previously defined struct/union:fred on line 2 of input57.c\n"
  },
  {
    "path": "37_Switch/tests/err.input59.c",
    "content": "Undeclared variable:y on line 3 of input59.c\n"
  },
  {
    "path": "37_Switch/tests/err.input60.c",
    "content": "Undeclared variable:x on line 3 of input60.c\n"
  },
  {
    "path": "37_Switch/tests/err.input61.c",
    "content": "Undeclared variable:x on line 3 of input61.c\n"
  },
  {
    "path": "37_Switch/tests/err.input64.c",
    "content": "undeclared enum type::fred on line 1 of input64.c\n"
  },
  {
    "path": "37_Switch/tests/err.input65.c",
    "content": "enum type redeclared::fred on line 2 of input65.c\n"
  },
  {
    "path": "37_Switch/tests/err.input66.c",
    "content": "enum value redeclared::z on line 2 of input66.c\n"
  },
  {
    "path": "37_Switch/tests/err.input68.c",
    "content": "redefinition of typedef:FOO on line 2 of input68.c\n"
  },
  {
    "path": "37_Switch/tests/err.input69.c",
    "content": "unknown type:FLOO on line 2 of input69.c\n"
  },
  {
    "path": "37_Switch/tests/err.input72.c",
    "content": "no loop or switch to break out from on line 1 of input72.c\n"
  },
  {
    "path": "37_Switch/tests/err.input73.c",
    "content": "no loop to continue to on line 1 of input73.c\n"
  },
  {
    "path": "37_Switch/tests/err.input75.c",
    "content": "Unexpected token in switch:27 on line 4 of input75.c\n"
  },
  {
    "path": "37_Switch/tests/err.input76.c",
    "content": "No cases in switch on line 3 of input76.c\n"
  },
  {
    "path": "37_Switch/tests/err.input77.c",
    "content": "case or default after existing default on line 6 of input77.c\n"
  },
  {
    "path": "37_Switch/tests/err.input78.c",
    "content": "case or default after existing default on line 6 of input78.c\n"
  },
  {
    "path": "37_Switch/tests/err.input79.c",
    "content": "Duplicate case value on line 6 of input79.c\n"
  },
  {
    "path": "37_Switch/tests/input01.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "37_Switch/tests/input02.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "37_Switch/tests/input03.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "37_Switch/tests/input04.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "37_Switch/tests/input05.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "37_Switch/tests/input06.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "37_Switch/tests/input07.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "37_Switch/tests/input08.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "37_Switch/tests/input09.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "37_Switch/tests/input10.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "37_Switch/tests/input11.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "37_Switch/tests/input12.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "37_Switch/tests/input13.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "37_Switch/tests/input14.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input15.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input16.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input17.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input18.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input18a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input19.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input20.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input21.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input22.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input23.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input24.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input25.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input26.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input27.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input28.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input29.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input31.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "37_Switch/tests/input32.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "37_Switch/tests/input33.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "37_Switch/tests/input34.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input35.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "37_Switch/tests/input36.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "37_Switch/tests/input37.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "37_Switch/tests/input38.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "37_Switch/tests/input39.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "37_Switch/tests/input40.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "37_Switch/tests/input41.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "37_Switch/tests/input42.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "37_Switch/tests/input43.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "37_Switch/tests/input44.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "37_Switch/tests/input45.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "37_Switch/tests/input46.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "37_Switch/tests/input47.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "37_Switch/tests/input48.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "37_Switch/tests/input49.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "37_Switch/tests/input50.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "37_Switch/tests/input51.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "37_Switch/tests/input52.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "37_Switch/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input55.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input56.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "37_Switch/tests/input57.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "37_Switch/tests/input58.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input59.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "37_Switch/tests/input60.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "37_Switch/tests/input61.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "37_Switch/tests/input62.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input63.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input64.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "37_Switch/tests/input65.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "37_Switch/tests/input66.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "37_Switch/tests/input67.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input68.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "37_Switch/tests/input69.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "37_Switch/tests/input70.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input71.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input72.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "37_Switch/tests/input73.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "37_Switch/tests/input74.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "37_Switch/tests/input75.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "37_Switch/tests/input76.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "37_Switch/tests/input77.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "37_Switch/tests/input78.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "37_Switch/tests/input79.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "37_Switch/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i ../lib/printint.c\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "37_Switch/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "37_Switch/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "37_Switch/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "37_Switch/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "37_Switch/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "37_Switch/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "37_Switch/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "37_Switch/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "37_Switch/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "37_Switch/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "37_Switch/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "37_Switch/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "37_Switch/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "37_Switch/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "37_Switch/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "37_Switch/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "37_Switch/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "37_Switch/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "37_Switch/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "37_Switch/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "37_Switch/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "37_Switch/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "37_Switch/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "37_Switch/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "37_Switch/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "37_Switch/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "37_Switch/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "37_Switch/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "37_Switch/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "37_Switch/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "37_Switch/tests/out.input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "37_Switch/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "37_Switch/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "37_Switch/tests/out.input55.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "37_Switch/tests/out.input58.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "37_Switch/tests/out.input62.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "37_Switch/tests/out.input63.c",
    "content": "25\n"
  },
  {
    "path": "37_Switch/tests/out.input67.c",
    "content": "5\n17\n"
  },
  {
    "path": "37_Switch/tests/out.input70.c",
    "content": "56\n"
  },
  {
    "path": "37_Switch/tests/out.input71.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "37_Switch/tests/out.input74.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "37_Switch/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "37_Switch/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "37_Switch/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "37_Switch/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\t// XXX Fix soon\n    rsize = typesize(rtype, NULL);\t// XXX Fix soon\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "38_Dangling_Else/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "38_Dangling_Else/Readme.md",
    "content": "# Part 38: Dangling Else and More\n\nI started this part of our compiler writing journey hoping to fix up the \n[dangling else problem](https:en.wikipedia.org/wiki/Dangling_else). It turns out that\nwhat I actually had to do was restructure the way we parse a few things because I\nhad the parsing wrong in the first place.\n\nThis probably happened because I was keen to add functionality, but in the process\nI didn't step back enough and consider what we had been building. \n\nSo, let's see what mistakes in the compiler need fixing.\n\n## Fixing Up the For Grammar\n\nWe'll start with our FOR loop structure. Yes it works, but it isn't as general as\nit should be.\n\nUp to now, the BNF grammar for our FOR loop has been:\n\n```\nfor_statement: 'for' '(' preop_statement ';'\n                         true_false_expression ';'\n                         postop_statement ')' compound_statement  ;\n```\n\nHowever, the \n[BNF Grammar for C](https://www.lysator.liu.se/c/ANSI-C-grammar-y.html)\nhas this:\n\n```\nfor_statement:\n        | FOR '(' expression_statement expression_statement ')' statement\n        | FOR '(' expression_statement expression_statement expression ')' statement\n        ;\n\nexpression_statement\n        : ';'\n        | expression ';'\n        ;\n```\n\nand an `expression` is actually an expression list where expressions are separated\nby commas.\n\nThis means that all three clauses of a FOR loop can actually be expression lists.\nIf we were writing a \"full\" C compiler, this would end up being tricky.\nHowever, we are only writing a compiler for a *subset* of C, and therefore I don't have to \nmake our compiler deal with the full grammar for C.\n\nSo, I have changed the parser for the FOR loop to recognise this:\n\n```\nfor_statement: 'for' '(' expression_list ';'\n                         true_false_expression ';'\n                         expression_list ')' compound_statement  ;\n```\n\nThe middle clause is a single expression that must provide a true or false result.\nThe first and last clauses can be expression lists. This allows a FOR loop like\nthe one now in `tests/input80.c`:\n\n```c\n    for (x=0, y=1; x < 6; x++, y=y+2)\n```\n\n## Changes to `expression_list()`\n\nTo do the above, I need to modify the `for_statement()` parsing function to\ncall `expression_list()` to parse the list of expressions in the first and third\nclause.\n\nBut, in the existing compiler, `expression_list()` only allows the ')' token to\nend an expression list. Therefore, I've modified `expression_list()`\nin `expr.c` to get the end token as an argument. And in `for_statement()`\nin `stmt.c`, we now have this code:\n\n```c\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  ...\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n  ...\n  // Get the condition and the ';'.\n  condAST = binexpr(0);\n  semi();\n  ...\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n}\n```\n\nAnd the code in `expression_list()` now looks like this:\n\n```c\nstruct ASTnode *expression_list(int endtoken) {\n  ...\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression\n    child = binexpr(0);\n\n    // Build an A_GLUE AST node ...\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken) break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n```\n\n## Single and Compound Statements\n\nUp to now, I've forced the programmer using our compiler to always put code in\n'{' ... '}' for:\n\n + the true body of an IF statement\n + the false body of an IF statement\n + the body of a WHILE statement\n + the body of a FOR statement\n + the body after a 'case' clause\n + the body after a 'default' clause\n\nFor the first four statements in this list, we don't need curly brackets when\nthere is only a single statement, e.g.\n\n```c\n  if (x>5)\n    x= x - 16;\n  else\n    x++;\n```\n\nBut when there are multiple statements in the body, we *do* need a compound statement\nwhich is a set of single statements surrounded by curly brackets, e.g.\n\n```c\n  if (x>5)\n    { x= x - 16; printf(\"not again!\\n\"); }\n  else\n    x++;\n```\n\nBut, for some unknown reason, the code after a 'case' or 'default' clause in a\n'switch' statement can be a set of single statements and we don't need curly brackets!!\nWho was the crazy person who thought that was OK? An example:\n\n```c\n  switch (x) {\n    case 1: printf(\"statement 1\\n\");\n            printf(\"statement 2\\n\");\n            break;\n    default: ...\n  }\n```\n\nEven worse, this is also legal:\n\n```c\n  switch (x) {\n    case 1: {\n      printf(\"statement 1\\n\");\n      printf(\"statement 2\\n\");\n      break;\n    }\n    default: ...\n  }\n```\n\nTherefore, we need to be able to parse:\n\n + single statements\n + a set of statements which are surrounded by curly brackets\n + a set of statements which don't start with a '{', but end with one of 'case',\n   'default', or '}' if they started with '{'\n\nTo this end, I've modified the `compound_statement()` in `stmt.c` to take an argument:\n\n```c\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n    ...\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n```\n\nIf this function get's called with `inswitch` set to 1, then we have been\ncalled during the parsing of a 'switch' statement, so look for 'case', 'default' or '}'\nto end the compound statement. Otherwise, we are in a more typical '{' ... '}'\nsituation.\n\nNow, we also need to allow:\n\n + a single statement inside the body of an IF statement\n + a single statement inside the body of an WHILE statement\n + a single statement inside the body of a FOR statement\n\nAll of these are, at present, calling `compound_statement(0)`, but this\nenforces the parsing of a closing '}', and we won't have one of these for a single statement.\n\nThe answer is to get the IF, WHILE and FOR parsing code to call\n`single_statement()` to parse one statement. And, get `single_statement()`\nto call `compound_statement()` if it see an opening curly bracket.\n\nThus, I've also made these changes in `stmt.c`:\n\n```c\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  ...\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n}\n...\nstatic struct ASTnode *if_statement(void) {\n  ...\n  // Get the AST for the statement\n  trueAST = single_statement();\n  ...\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  ...\n}\n...\nstatic struct ASTnode *while_statement(void) {\n  ...\n    // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n  ...\n}\n...\nstatic struct ASTnode *for_statement(void) {\n  ...\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n  ...\n}\n```\n\nThis now means the compiler will accept code which looks like this:\n\n```c\n  if (x>5)\n    x= x - 16;\n  else\n    x++;\n```\n\n## Yes, But \"Dangling Else?\"\n\nI still haven't solved the \"dangling else\" problem, which after all is why\nI started this part of the journey. Well, it turns out that this problem was\nsolved due to the way that we already parse our input.\n\nConsider this program:\n\n```c\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n```\n\nWe want the 'else' code to pair up with the nearest 'if' statement. Therefore,\nthe last `printf` statement above should only print when `x` is between 5 and 10.\nThe 'else' code should *not* be invoked due to the opposite of `x > 5`.\n\nLuckily, in our `if_statement()` parser, we greedily scan for any 'else' token\nafter the body of the IF statement:\n\n```c\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n```\n\nThis forces the 'else' to pair up with the nearest 'if' and solves the dangling else\nproblem. So, all this time, I was forcing the use of '{' ... '}' when I'd already\nsolved the problem I was worrying about! Sigh.\n\n## Some Better Debug Output\n\nFinally, I've made a change to our scanner to improve debugging. Or, more exactly,\nto improve the debug messages that we print out. Up to now, we have been printing\nthe token numeric value in our error messages, e.g.\n\n + Unexpected token in parameter list: 23\n + Expecting a primary expression, got token: 19\n + Syntax error, token: 44\n\nFor the programmer who receives these error messages, they are essentially unusable.\nIn `scan.c`, I've added this list of token strings:\n\n```c\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n```\n\nIn `defs.h`, I've added another field to the Token structure:\n\n```c\n// Token structure\nstruct token {\n  int token;                    // Token type, from the enum list above\n  char *tokstr;                 // String version of the token\n  int intvalue;                 // For T_INTLIT, the integer value\n};\n```\n\nIn `scan()` in `scan.c`, just before we return a token, we set up its\nstring equivalent:\n\n```c\n  t->tokstr = Tstring[t->token];\n```\n\nAnd, finally, I've modified a bunch of `fatalXX()` calls to print out the\n`tokstr` field of the current token instead of the `intvalue` field. This\nmeans we now see:\n\n + Unexpected token in parameter list: ==\n + Expecting a primary expression, got token: ]\n + Syntax error, token: >>\n\nwhich is much better.\n\n\n## Conclusion and What's Next\n\nI set out to solve the \"dangling else\" misfeature in our compiler and ended up\nfixing a bunch of other misfeatures. In the process, I found out that there was\nno \"dangling else\" problem to solve.\n\nWe have reached a stage in the development of the compiler where all the essential\nelements we need to self-compile the compiler are implemented, but now we need to\nfind and fix a bunch of small issues. This is the \"mop up\" phase.\n\nWhat this means is, from now on, there will be less and less on how to write\na compiler, and more and more on how to fix a broken compiler. I won't be\ndisappointed if you choose to bail out on the future parts of our journey.\nIf you do, I hope that you found all the parts of the journey so far useful.\n\nIn the next part of our compiler writing journey, I will pick something that\ncurrently doesn't work but we need to work to self-compile our compiler, and\nfix it. [Next step](../39_Var_Initialisation_pt1/Readme.md)\n"
  },
  {
    "path": "38_Dangling_Else/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      for (int i = 0; i < size; i++)\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "38_Dangling_Else/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "38_Dangling_Else/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  // original version\n  for (int i = 0; i < node->size; i++) {\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(size) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", node->size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", node->size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", node->size);\n      break;\n    default:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "38_Dangling_Else/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "38_Dangling_Else/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic void enum_declaration(void);\nint typedef_declaration(struct symtable **ctype);\nint type_of_typedef(char *name, struct symtable **ctype);\n\n\n// Parse the current token and return a\n// primitive type enum value, a pointer\n// to any composite type and possibly\n// modify the class of the type.\n// Also scan in the next token.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic=1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN: *class= C_EXTERN; scan(&Token); break;\n      default: exstatic= 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n\n  // Scan in one or more further '*' tokens \n  // and determine the correct pointer type\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n\n  // We leave with the next token already scanned\n  return (type);\n}\n\n// variable_declaration: type identifier ';'\n//        | type identifier '[' INTLIT ']' ';'\n//        ;\n//\n// Parse the declaration of a scalar variable or an array\n// with a given size.\n// The identifier has been scanned & we have the type.\n// class is the variable's class\n// Return the pointer to variable's entry in the symbol table\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class) {\n  struct symtable *sym = NULL;\n\n  // See if this has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      if (findglob(Text) != NULL)\n\tfatals(\"Duplicate global variable declaration\", Text);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(Text) != NULL)\n\tfatals(\"Duplicate local variable declaration\", Text);\n    case C_MEMBER:\n      if (findmember(Text) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", Text);\n  }\n\n  // Text now has the identifier's name.\n  // If the next token is a '['\n  if (Token.token == T_LBRACKET) {\n    // Skip past the '['\n    scan(&Token);\n\n    // Check we have an array size\n    if (Token.token == T_INTLIT) {\n      // Add this as a known array and generate its space in assembly.\n      // We treat the array as a pointer to its elements' type\n      switch (class) {\n\tcase C_EXTERN:\n\tcase C_GLOBAL:\n\t  sym =\n\t    addglob(Text, pointer_to(type), ctype, S_ARRAY, class, Token.intvalue);\n\t  break;\n\tcase C_LOCAL:\n\tcase C_PARAM:\n\tcase C_MEMBER:\n\t  fatal\n\t    (\"For now, declaration of non-global arrays is not implemented\");\n      }\n    }\n    // Ensure we have a following ']'\n    scan(&Token);\n    match(T_RBRACKET, \"]\");\n  } else {\n    // Add this as a known scalar\n    // and generate its space in assembly\n    switch (class) {\n      case C_EXTERN:\n      case C_GLOBAL:\n\tsym = addglob(Text, type, ctype, S_VARIABLE, class, 1);\n\tbreak;\n      case C_LOCAL:\n\tsym = addlocl(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_PARAM:\n\tsym = addparm(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n      case C_MEMBER:\n\tsym = addmemb(Text, type, ctype, S_VARIABLE, 1);\n\tbreak;\n    }\n  }\n  return (sym);\n}\n\n// var_declaration_list: <null>\n//           | variable_declaration\n//           | variable_declaration separate_token var_declaration_list ;\n//\n// When called to parse function parameters, separate_token is ','.\n// When called to parse members of a struct/union, separate_token is ';'.\n//\n// Parse a list of variables.\n// Add them as symbols to one of the symbol table lists, and return the\n// number of variables. If funcsym is not NULL, there is an existing function\n// prototype, so compare each variable's type against this prototype.\nstatic int var_declaration_list(struct symtable *funcsym, int class,\n\t\t\t\tint separate_token, int end_token) {\n  int type;\n  int paramcnt = 0;\n  struct symtable *protoptr = NULL;\n  struct symtable *ctype;\n\n  // If there is a prototype, get the pointer\n  // to the first prototype parameter\n  if (funcsym != NULL)\n    protoptr = funcsym->member;\n\n  // Loop until the final end token\n  while (Token.token != end_token) {\n    // Get the type and identifier\n    type = parse_type(&ctype, &class);\n    ident();\n\n    // Check that this type matches the prototype if there is one\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    } else {\n      // Add a new parameter to the right symbol table list, based on the class\n      var_declaration(type, ctype, class);\n    }\n    paramcnt++;\n\n    // Must have a separate_token or ')' at this point\n    if ((Token.token != separate_token) && (Token.token != end_token))\n      fatals(\"Unexpected token in parameter list\", Token.tokstr);\n    if (Token.token == separate_token)\n      scan(&Token);\n  }\n\n  // Check that the number of parameters in this list matches\n  // any existing prototype\n  if ((funcsym != NULL) && (paramcnt != funcsym->nelems))\n    fatals(\"Parameter count mismatch for function\", funcsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\n// The identifier has been scanned & we have the type.\nstruct ASTnode *function_declaration(int type) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(Text)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym = addglob(Text, type, NULL, S_FUNCTION, C_GLOBAL, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = var_declaration_list(oldfuncsym, C_PARAM, T_COMMA, T_RPAREN);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    scan(&Token);\n    return (NULL);\n  }\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel= 0;\n  Switchlevel= 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Return an A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  return (mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel));\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  int offset;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text, P_STRUCT, NULL, 0, 0);\n  else\n    ctype = addunion(Text, P_UNION, NULL, 0, 0);\n  scan(&Token);\n\n  // Scan in the list of members and attach\n  // to the struct type's node\n  var_declaration_list(NULL, C_MEMBER, T_SEMI, T_RBRACE);\n  rbrace();\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->posn = genalign(m->type, offset, 1);\n    else\n      m->posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nint typedef_declaration(struct symtable **ctype) {\n  int type, class=0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0) \n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype, 0, 0);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nint type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct ASTnode *tree;\n  struct symtable *ctype;\n  int type, class= C_GLOBAL;\n\n  while (1) {\n    // Stop when we have reached EOF\n    if (Token.token == T_EOF)\n      break;\n\n    // Get the type\n    type = parse_type(&ctype, &class);\n\n    // We might have just parsed a struct, union or enum\n    // declaration with no associated variable.\n    // The next token might be a ';'. Loop back if it is.\n    // XXX: I'm not happy with this as it allows\n    // \"struct fred;\" as an accepted statement\n    if (type == -1) {\n      semi();\n      continue;\n    }\n    // We have to read past the identifier\n    // to see either a '(' for a function declaration\n    // or a ',' or ';' for a variable declaration.\n    // Text is filled in by the ident() call.\n    ident();\n    if (Token.token == T_LPAREN) {\n\n      // Parse the function declaration\n      tree = function_declaration(type);\n\n      // Only a function prototype, no code\n      if (tree == NULL)\n\tcontinue;\n\n      // A real function, generate the assembly code for it\n      if (O_dumpAST) {\n\tdumpAST(tree, NOLABEL, 0);\n\tfprintf(stdout, \"\\n\\n\");\n      }\n      genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n      // Now free the symbols associated\n      // with this function\n      freeloclsyms();\n    } else {\n\n      // Parse the global variable declaration\n      // and skip past the trailing semicolon\n      var_declaration(type, ctype, class);\n      semi();\n    }\n  }\n}\n"
  },
  {
    "path": "38_Dangling_Else/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint size, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int size);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addunion(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nstruct symtable *var_declaration(int type, struct symtable *ctype, int class);\nstruct ASTnode *function_declaration(int type);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint parse_type(struct symtable **ctype, int *class);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "38_Dangling_Else/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  union {\n    int size;\t\t\t// Number of elements in the symbol\n    int endlabel;\t\t// For functions, the end label\n  };\n  union {\n    int nelems;\t\t\t// For functions, # of params\n    int posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  };\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  union {\t\t\t// the symbol in the symbol table\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "38_Dangling_Else/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken) break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n        tokentype == T_COLON) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "38_Dangling_Else/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs();\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs();\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL) genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      if (n->right != NULL) genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "38_Dangling_Else/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "38_Dangling_Else/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "38_Dangling_Else/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "38_Dangling_Else/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "38_Dangling_Else/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "38_Dangling_Else/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and get the compound expression\n\tmatch(T_COLON, \":\");\n\tleft= compound_statement(1); casecount++;\n\n\t// Build a sub-tree with the compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  int type, class = C_LOCAL;\n  struct symtable *ctype;\n  struct ASTnode *stmt;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration.\n      // Parse the type and get the identifier.\n      // Then parse the rest of the declaration\n      // and skip over the semicolon\n      type = parse_type(&ctype, &class);\n      ident();\n      var_declaration(type, ctype, class);\n      semi();\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "38_Dangling_Else/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int size, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->size = size;\n  node->posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(node);\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, size, 0);\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, size, 0);\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, size, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, size, 0);\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_STRUCT, size, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_UNION, size, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_TYPEDEF, size, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input31.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input32.c",
    "content": "Unknown variable:cow on line 4 of input32.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input33.c",
    "content": "Incompatible type to return on line 4 of input33.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input34.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input34.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 4 of input35.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input36.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input37.c",
    "content": "Unexpected token in parameter list:+ on line 3 of input37.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input38.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 4 of input39.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input40.c",
    "content": "No return for function with non-void type on line 4 of input40.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input41.c",
    "content": "Can't return from a void function on line 3 of input41.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input42.c",
    "content": "Undeclared function:fred on line 3 of input42.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input43.c",
    "content": "Undeclared array:b on line 3 of input43.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input44.c",
    "content": "Unknown variable:z on line 3 of input44.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 3 of input45.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input46.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 3 of input47.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 3 of input48.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 6 of input49.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 6 of input50.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input51.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 5 of input52.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input56.c",
    "content": "unknown struct/union type:var1 on line 2 of input56.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input57.c",
    "content": "previously defined struct/union:fred on line 2 of input57.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input59.c",
    "content": "Undeclared variable:y on line 3 of input59.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input60.c",
    "content": "Undeclared variable:x on line 3 of input60.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input61.c",
    "content": "Undeclared variable:x on line 3 of input61.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input64.c",
    "content": "undeclared enum type::fred on line 1 of input64.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input65.c",
    "content": "enum type redeclared::fred on line 2 of input65.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input66.c",
    "content": "enum value redeclared::z on line 2 of input66.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input68.c",
    "content": "redefinition of typedef:FOO on line 2 of input68.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input69.c",
    "content": "unknown type:FLOO on line 2 of input69.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input72.c",
    "content": "no loop or switch to break out from on line 1 of input72.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input73.c",
    "content": "no loop to continue to on line 1 of input73.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input75.c",
    "content": "Unexpected token in switch:if on line 4 of input75.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input76.c",
    "content": "No cases in switch on line 3 of input76.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input77.c",
    "content": "case or default after existing default on line 6 of input77.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input78.c",
    "content": "case or default after existing default on line 6 of input78.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/err.input79.c",
    "content": "Duplicate case value on line 6 of input79.c\n"
  },
  {
    "path": "38_Dangling_Else/tests/input01.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input02.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input03.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input04.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input05.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input06.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input07.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input08.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input09.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input10.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input11.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input12.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input13.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input14.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input15.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input16.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input17.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input18.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input18a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input19.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input20.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input21.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input22.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input23.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input24.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input25.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input26.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input27.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input28.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input29.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input31.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input32.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input33.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input34.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input35.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input36.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "38_Dangling_Else/tests/input37.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "38_Dangling_Else/tests/input38.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "38_Dangling_Else/tests/input39.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "38_Dangling_Else/tests/input40.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "38_Dangling_Else/tests/input41.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "38_Dangling_Else/tests/input42.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "38_Dangling_Else/tests/input43.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "38_Dangling_Else/tests/input44.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "38_Dangling_Else/tests/input45.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "38_Dangling_Else/tests/input46.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "38_Dangling_Else/tests/input47.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "38_Dangling_Else/tests/input48.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "38_Dangling_Else/tests/input49.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input50.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input51.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input52.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input55.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input56.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "38_Dangling_Else/tests/input57.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "38_Dangling_Else/tests/input58.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input59.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input60.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input61.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input62.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input63.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input64.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "38_Dangling_Else/tests/input65.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "38_Dangling_Else/tests/input66.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "38_Dangling_Else/tests/input67.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input68.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "38_Dangling_Else/tests/input69.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "38_Dangling_Else/tests/input70.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input71.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input72.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "38_Dangling_Else/tests/input73.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "38_Dangling_Else/tests/input74.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input75.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input76.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input77.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input78.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input79.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input80.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input81.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input82.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/input83.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "38_Dangling_Else/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input55.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input58.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input62.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input63.c",
    "content": "25\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input67.c",
    "content": "5\n17\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input70.c",
    "content": "56\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input71.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input74.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input80.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input81.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input82.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "38_Dangling_Else/tests/out.input83.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "38_Dangling_Else/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "38_Dangling_Else/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "38_Dangling_Else/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "38_Dangling_Else/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\t// XXX Fix soon\n    rsize = typesize(rtype, NULL);\t// XXX Fix soon\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/Readme.md",
    "content": "# Part 39: Variable Initialisation, part 1\n\nWe can declare variables in the language that our compiler accepts, but\nwe can't initialise them at the same time. So in this part (and the following parts)\nI will work on fixing this.\n\nIt's worth thinking about this now before we do any actual implementation\nbecause, hopefully, I can devise a way to share some of the code. So\nI might do a bit of a \"brain dump\" below to help me think about the problem.\n\nRight now, we can declare variables in three places:\n\n  + Global variables are declared outside of any function\n  + Function parameters are declared in a parameter list\n  + Local variables are declared inside of a function\n\nEach declaration includes a description of the variable's type and its name.\n\nIn terms of initialisation:\n\n  + We can't initialise function parameters, as they will get\n    values copied in from the function caller's arguments.\n  + Global variables cannot be initialised with an expression,\n    as there is no function in which the expression assembly code\n    can run.\n  + Local variables can be initialised with an expression.\n\nWe also want to have a list of variable names after the type definition.\nThis means that there will some similarities and some differences to\ndeal with. In semi-BNF syntax:\n\n```\nglobal_declaration: type_definition global_var_list ';' ;\n\nglobal_var_list: global_var\n               | global_var ',' global_var_list  ;\n\nglobal_var: variable_name\n          | variable_name '=' literal_value ;\n\nlocal_declaration: type_definition local_var_list ';' ;\n\nlocal_var_list: local_var\n              | local_var ',' local_var_list  ;\n\nlocal_var: variable_name\n         | variable_name '=' expression ;\n\nparameter_list: parameter\n              | parameter ',' parameter_list ;\n\nparameter: type_definition variable_name ;\n```\nHere is a set of examples that I do want to\nsupport in our compiler.\n\n### Global Declarations\n\n```c\n  int   x= 5;\n  int   a, b= 7, c, d= 6;\n  char *e, f;                           // e is a pointer, f isn't!\n  char  g[]= \"Hello\", *h= \"foo\";\n  int   j[]= { 1, 2, 3, 4, 5 };\n  char *k[]= { \"fish\", \"cat\", \"ball\" };\n  int   l[70];\n```\n\nThe comment I added has deep implications. We will have to parse the\ntype at the front and, for *each* following variable, parse any prefix\n'*' or postfix '[ ]' to decide if it's a pointer or an array.\n\nI will only deal with a single dimensional list of initialisation values\nas shown in the examples above.\n\n### Local Declarations\n\nThe above examples also apply, but we should also be able to do these local declarations:\n\n```c\n  int u= x + 3;\n  char *v= k[0];\n  char *w= k[b-6];\n  int y= 2*b+c, z= l[d] + j[2*x+5];\n```\n\nI was going to offer to parse\n`int list[]= { x+2, a+b, c*d, u+j[3], j[x] + j[a] };`\nbut that looks like an absolute nightmare to deal with, so I think I will\nstick with either a list of literal values, or not even allow array\ninitialisation in local scope.\n\n## Now What?\n\nRight now, after looking at the above examples, I'm kind of terrified!\nI think I can do the global variable initialisation, but I'll have to\nrewrite how I parse the types of each individual variable in a list.\nThen I can parse the '='.\n\nIf we are in global scope, I'll call a function to parse the literal values.\n\nIf in local scope, I can't use the existing `binexpr()` function because\nit parses the variable name on the left and makes an lvalue AST node for it\ninternally. Perhaps I can hand-build this lvalue AST node and pass the\npointer to it into `binexpr()`. Then I can add code to `binexpr()` that says:\n\n```\n  if we got an lvalue pointer {\n    set left to this pointer\n  } else {\n    left = prefix();\n    deal with the operator token\n  }\n  rest of the existing code\n```\n\nOk, so I have a sort-of plan. I'll do some refactoring first.\nAnd the first task is to work out how to rewrite the parsing of\ntypes and variable names so that we can parse lists of them.\n\n## A Look at the Refactoring\n\nSo I've just done the refactoring of the code and it feels like I've just\nrearranged code but that's not entirely true. So what I'll do is show you\nhow all the new functions call each other, and then outline what each one does.\n\nI've drawn a call graph of the code in the new `decl.c`:\n\n![](Figs/decl_call_graph.png)\n\nAt the top, `global_declarations()` is called to parse anything which is\nglobal. It simply loops and calls `declaration list()`. Alternatively,\nwe are in a function and we've hit a type token (`int`, `char` etc.). We\ncall `declaration_list()` to parse what should be a variable.\n\n`declaration_list()` is new. It calls `parse_type()` to get the type\n(e.g. `int`, `char`, a struct, union or typedef etc.). This is the\n*base type* of a list, but each thing in the list can modify this type.\nAs an example:\n\n```c\n  int a, *b, c[40], *d[100];\n```\n\nSo in `declaration_list()` we loop for each declaration in the list.\nFor each declaration, we call `parse_stars()` to see how the\nbase type is modified. At this point we can parse the identifier of\nthe individual declaration, and this is done in `symbol_declaration()`.\nBased on what token follows, we call:\n\n  + `function_declaration()` for functions,\n  + `array_declaration` for arrays, or\n  + `scalar_delaration` for scalar variables\n\nIn a function declaration, there can be parameters, so\n`parameter_declaration_list()` is invoked to do this. Of course, the parameter\nlist is a declaration, so we call `declaration_list()` to deal with this!\n\nOver on the left we have `parse_type()`. This gets ordinary types like\n`int` and `char`, but this is where new types such as structs, unions,\nenums and typedefs are also parsed.\n\nParsing a typedef in `typedef_declaration()` should be easy because there\nis an existing type which we are aliasing. However, we can also write this:\n\n```c\ntypedef char * charptr;\n```\n\nBecause `parse_type()` doesn't deal with any `*` tokens,\n`typedef_declaration()` has to manually call `parse_stars()` to see how the\nbase type is modified before creating the alias.\n\nAny enum declaration is handled by `enum_declaration`. For structs and\nunions, we call `composite_declaration()`. And guess what?! The members\ninside a new struct or union form a list of member declarations, so we\ncall `declaration_list()` to parse them!\n\n## Regression Testing\n\nI'm so glad that I now have about eighty individual tests, because there\nis no way I could safely refactor `decl.c` without being able to confirm\nthat the new code still produces the same errors or assembly output as\nbefore.\n\n## New Functionality\n\nAlthough this part of the journey is mostly a redesign to get ready for\nvariable initialisation, we now support lists in global and local variable\ndeclarations. Therefore, I have new tests:\n\n```c\n// tests/input84.c, locals\nint main() {\n  int x, y;\n  x=2; y=3;\n  ..\n}\n\n//input88.c, globals\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n```\n\n## Conclusion and What's Next\n\nI feel a bit happier now that I've got the compiler to parse a list\nof variables following a type, e.g. `int a, *b, **c;`. I've also\nput comments into the code where I will have to write the assignment\nfunctionality to go with declarations.\n\nIn the next part of our compiler writing journey, we will try to add\nglobal variable declarations with assignments to our compiler. [Next step](../40_Var_Initialisation_pt2/Readme.md)\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t0\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t0\\n\");\n      break;\n    case 8:\n      fprintf(Outfile, \"\\t.quad\\t0\\n\");\n      break;\n    default:\n      for (int i = 0; i < size; i++)\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n  // Get the size of the type\n  size = typesize(node->type, node->ctype);\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\", node->name);\n\n  // Generate the space for this type\n  // original version\n  for (int i = 0; i < node->size; i++) {\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t0\\n\");\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t0\\n\");\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tdq\\t0\\n\");\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n    }\n  }\n\n  /* compact version using times instead of loop\n  switch(size) {\n    case 1:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", node->size);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdd\\t0\\n\", node->size);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdq\\t0\\n\", node->size);\n      break;\n    default:\n      fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n  }\n  */\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nstatic int parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nstatic int parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class) {\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      return (addglob(varname, type, ctype, S_VARIABLE, class, 1));\n      break;\n    case C_LOCAL:\n      return (addlocl(varname, type, ctype, S_VARIABLE, 1));\n      break;\n    case C_PARAM:\n      return (addparm(varname, type, ctype, S_VARIABLE, 1));\n      break;\n    case C_MEMBER:\n      return (addmemb(varname, type, ctype, S_VARIABLE, 1));\n      break;\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n  struct symtable *sym;\n  // Skip past the '['\n  scan(&Token);\n\n  // Check we have an array size\n  if (Token.token == T_INTLIT) {\n    // Add this as a known array\n    // We treat the array as a pointer to its elements' type\n    switch (class) {\n      case C_EXTERN:\n      case C_GLOBAL:\n\tsym =\n\t  addglob(varname, pointer_to(type), ctype, S_ARRAY, class,\n\t\t  Token.intvalue);\n\tbreak;\n      case C_LOCAL:\n      case C_PARAM:\n      case C_MEMBER:\n\tfatal(\"For now, declaration of non-global arrays is not implemented\");\n    }\n  }\n  // Ensure we have a following ']'\n  scan(&Token);\n  match(T_RBRACKET, \"]\");\n  return (sym);\n}\n\n\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, C_GLOBAL, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Generate the assembly code for it\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text, P_STRUCT, NULL, 0, 0);\n  else\n    ctype = addunion(Text, P_UNION, NULL, 0, 0);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t= declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE);\n    if (t== -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead==NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->posn = genalign(m->type, offset, 1);\n    else\n      m->posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype, 0, 0);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\nstatic void array_initialisation(struct symtable *sym, int type,\n\t\t\t\t struct symtable *ctype, int class) {\n  fatal(\"No array initialisation yet!\");\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n  int stype = S_VARIABLE;\n  // struct ASTnode *expr = NULL;\n\n  // Assume it will be a scalar variable.\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET) {\n    sym = array_declaration(varname, type, ctype, class);\n    stype = S_ARRAY;\n  } else\n    sym = scalar_declaration(varname, type, ctype, class);\n\n  // The array or scalar variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Not possible for a parameter or member\n    if (class == C_PARAM)\n      fatals(\"Initialisation of a parameter not permitted\", varname);\n    if (class == C_MEMBER)\n      fatals(\"Initialisation of a member not permitted\", varname);\n    scan(&Token);\n\n    // Array initialisation\n    if (stype == S_ARRAY)\n      array_initialisation(sym, type, ctype, class);\n    else {\n      fatal(\"Scalar variable initialisation not done yet\");\n      // Variable initialisation\n      // if (class== C_LOCAL)\n      // Local variable, parse the expression\n      // expr= binexpr(0);\n      // else write more code!\n    }\n  }\n  // Generate the storage for the array or scalar variable. SOON.\n  // genstorage(sym, expr);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2) {\n  int inittype, type;\n  struct symtable *sym;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL)\n        fatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint size, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int size);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addunion(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype, int stype, int size);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nint declaration_list(struct symtable **ctype, int class, int et1, int et2);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  union {\n    int size;\t\t\t// Number of elements in the symbol\n    int endlabel;\t\t// For functions, the end label\n  };\n  union {\n    int nelems;\t\t\t// For functions, # of params\n    int posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  };\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  union {\t\t\t// the symbol in the symbol table\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken) break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if ((Token.intvalue) >= 0 && (Token.intvalue < 256))\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n        tokentype == T_COLON) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs();\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs();\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL) genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      if (n->right != NULL) genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and get the compound expression\n\tmatch(T_COLON, \":\");\n\tleft= compound_statement(1); casecount++;\n\n\t// Build a sub-tree with the compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF);\n      semi();\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int size, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->size = size;\n  node->posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(node);\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, size, 0);\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, size, 0);\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, size, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, size, 0);\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_STRUCT, size, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_UNION, size, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype,\n\t\t\t   int stype, int size) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_TYPEDEF, size, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input31.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input32.c",
    "content": "Unknown variable:cow on line 4 of input32.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input33.c",
    "content": "Incompatible type to return on line 4 of input33.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input34.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input34.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 4 of input35.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input36.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input37.c",
    "content": "Expected:comma on line 3 of input37.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input38.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 4 of input39.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input40.c",
    "content": "No return for function with non-void type on line 4 of input40.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input41.c",
    "content": "Can't return from a void function on line 3 of input41.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input42.c",
    "content": "Undeclared function:fred on line 3 of input42.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input43.c",
    "content": "Undeclared array:b on line 3 of input43.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input44.c",
    "content": "Unknown variable:z on line 3 of input44.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 3 of input45.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input46.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 3 of input47.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 3 of input48.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 6 of input49.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 6 of input50.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input51.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 5 of input52.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input56.c",
    "content": "unknown struct/union type:var1 on line 2 of input56.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input57.c",
    "content": "previously defined struct/union:fred on line 2 of input57.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input59.c",
    "content": "Undeclared variable:y on line 3 of input59.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input60.c",
    "content": "Undeclared variable:x on line 3 of input60.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input61.c",
    "content": "Undeclared variable:x on line 3 of input61.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input64.c",
    "content": "undeclared enum type::fred on line 1 of input64.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input65.c",
    "content": "enum type redeclared::fred on line 2 of input65.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input66.c",
    "content": "enum value redeclared::z on line 2 of input66.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input68.c",
    "content": "redefinition of typedef:FOO on line 2 of input68.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input69.c",
    "content": "unknown type:FLOO on line 2 of input69.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input72.c",
    "content": "no loop or switch to break out from on line 1 of input72.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input73.c",
    "content": "no loop to continue to on line 1 of input73.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input75.c",
    "content": "Unexpected token in switch:if on line 4 of input75.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input76.c",
    "content": "No cases in switch on line 3 of input76.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input77.c",
    "content": "case or default after existing default on line 6 of input77.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input78.c",
    "content": "case or default after existing default on line 6 of input78.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input79.c",
    "content": "Duplicate case value on line 6 of input79.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input85.c",
    "content": "Bad type in parameter list on line 1 of input85.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input86.c",
    "content": "Function definition not at global level on line 3 of input86.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/err.input87.c",
    "content": "Bad type in member list on line 4 of input87.c\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input01.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input02.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input03.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input04.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input05.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input06.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input07.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input08.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input09.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input10.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input11.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input12.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input13.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input14.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input15.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input16.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input17.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input18.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input18a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input19.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input20.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input21.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input22.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input23.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input24.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input25.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input26.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input27.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input28.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input29.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input31.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input32.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input33.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input34.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input35.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input36.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input37.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input38.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input39.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input40.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input41.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input42.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input43.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input44.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input45.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input46.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input47.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input48.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input49.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input50.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input51.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input52.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input55.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input56.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input57.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input58.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input59.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input60.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input61.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input62.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input63.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input64.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input65.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input66.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input67.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input68.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input69.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input70.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input71.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input72.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input73.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input74.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input75.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input76.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input77.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input78.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input79.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input80.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input81.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input82.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input83.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input84.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input85.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input86.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input87.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/input88.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input55.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input58.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input62.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input63.c",
    "content": "25\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input67.c",
    "content": "5\n17\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input70.c",
    "content": "56\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input71.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input74.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input80.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input81.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input82.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input83.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input84.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/out.input88.c",
    "content": "5 6\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "39_Var_Initialisation_pt1/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\t// XXX Fix soon\n    rsize = typesize(rtype, NULL);\t// XXX Fix soon\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/Readme.md",
    "content": "# Part 40: Global Variable Initialisation\n\nIn the previous part of our compiler writing journey, I started the\ngroundwork to add variable declarations to our language. I've been\nable to implement this for global scalar and array variables in this\npart of our compiler writing journey.\n\nAt the same time, I realised that I hadn't designed the symbol table\nstructure to properly deal with the size of a variable and the number\nof elements in an array variable. So half of this part is going to\nbe a rewrite of some of the code that deals with the symbol table.\n\n## A Quick Recap for Global Variable Assignments\n\nAs a quick recap, below are a set of example global variable assignments\nthat I want to support:\n\n```c\nint x= 2;\nchar y= 'a';\nchar *str= \"Hello world\";\nint a[10];\nchar b[]= { 'q', 'w', 'e', 'r', 't', 'y' };\nchar c[10]= { 'q', 'w', 'e', 'r', 't', 'y' };   // Zero padded\nchar *d[]= { \"apple\", \"banana\", \"peach\", \"pear\" };\n```\n\nI'm not going to deal with initialisation of global structs or unions.\nAlso, for now, I'm not going to deal with putting NULL into `char *`\nvariables. I'll come back to that later, if we need it.\n\n## Where We Go To\n\nIn the last part of the journey, I'd written this in `decl.c`:\n\n```c\nstatic struct symtable *symbol_declaration(...) {\n  ...\n  // The array or scalar variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    ...\n        // Array initialisation\n    if (stype == S_ARRAY)\n      array_initialisation(sym, type, ctype, class);\n    else {\n      fatal(\"Scalar variable initialisation not done yet\");\n      // Variable initialisation\n      // if (class== C_LOCAL)\n      // Local variable, parse the expression\n      // expr= binexpr(0);\n      // else write more code!\n    }\n  }\n  ...\n}\n```\n\ni.e. I knew where to put the code but I didn't know what code to write. First up, we need to parse some literal values...\n\n## Scalar Variable Initialisation\n\nWe are going to need to parse integer and string literals, as these are the\nonly things which we can assign to global variables. We need to ensure\nthat the type of each literal is compatible with the variable type that we\nare assigning. To this end, there's a new function in `decl.c`:\n\n```c\n// Given a type, check that the latest token is a literal\n// of that type. If an integer literal, return this value.\n// If a string literal, return the label number of the string.\n// Do not scan the next token.\nint parse_literal(int type) {\n\n  // We have a string literal. Store in memory and return the label\n  if ((type == pointer_to(P_CHAR)) && (Token.token == T_STRLIT))\n    return(genglobstr(Text));\n\n  if (Token.token == T_INTLIT) {\n    switch(type) {\n      case P_CHAR: if (Token.intvalue < 0 || Token.intvalue > 255)\n                     fatal(\"Integer literal value too big for char type\");\n      case P_INT:\n      case P_LONG: break;\n      default: fatal(\"Type mismatch: integer literal vs. variable\");\n    }\n  } else\n    fatal(\"Expecting an integer literal value\");\n  return(Token.intvalue);\n}\n```\n\nThe first IF statement ensures that we can do:\n\n```c\nchar *str= \"Hello world\";\n```\n\nand it returns the label number of the address where the string is stored.\n\nFor integer literals, we check the range when we are assigning to a `char`\nvariable. And for any other token type, we have a fatal error.\n\n## Changes to the Symbol Table Structure\n\nThe above function always returns an integer, regardless of what type of\nliteral it parses. Now we need a location in each variable's symbol entry\nto store this. So, I've added (and/or modified) these fields in the\nsymbol entry structure in `defs.h`:\n\n```c\n// Symbol table structure\nstruct symtable {\n  ...\n  int size;              // Total size in bytes of this symbol\n  int nelems;            // Functions: # params. Arrays: # elements\n  ...\n  int *initlist;         // List of initial values\n  ...\n};\n```\n\nFor a scalar with one initial value, or for an array with several initial\nvalues, we store a count of elements in `nelems` and attach a list of\ninteger values to `initlist`. Let's look at assignment to a scalar variable.\n\n## Assignment to Scalar Variables\n\nThe `scalar_declaration()` function is modified as follows:\n\n```c\nstatic struct symtable *scalar_declaration(...) {\n  ...\n    // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n      scan(&Token);\n    }                           // No else code yet, soon\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n\n  return (sym);\n}\n```\n\nWe ensure that the assignment can only occur in global or local context,\nand we skip over the '=' token. We set up an `initlist` of exactly one\nand call `parse_literal()` with the type of this variable to get the\nliteral value (or the label number of a string). Then we skip the\nliteral value to get to the following token (either a ',' or a ';').\n\nPreviously, the `sym` symbol table entry was created with `addglob()`\nand the number of elements was set to one. I'll cover this change soon.\n\nWe now move the call to `genglobsym()` (which previously was in `addglob()`\nto here, and we wait until the initial value is stored in the `sym` entry.\nThis ensures that the literal we just parsed will be put into the storage\nfor the variable in memory.\n\n### Scalar Initialisation Examples\n\nAs a quick example:\n\n```c\nint x= 5;\nchar *y= \"Hello\";\n```\n\ngenerates:\n\n```\n        .globl  x\nx:\n        .long   5\n\nL1:\n        .byte   72\n        .byte   101\n        .byte   108\n        .byte   108\n        .byte   111\n        .byte   0\n\n        .globl  y\ny:\n        .quad   L1\n```\n\n## Changes to the Symbol Table Code\n\nBefore we get to the parsing of array intialisation, we need to detour\nover to the changes to the symbol table code. As I highlighted before,\nmy original code didn't properly handle the storage of the size of a\nvariable nor the number of elements in an array. Let's look at the\nchanges I've made to do this.\n\nFirstly, we have a bug fix. In `types.c`:\n\n```c\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n```\n\nPreviously, there was no test against P_CHAR, so a `void` type was\ntreated as an integer type. Oops!\n\nIn `sym.c` we now deal with the fact that each variable now has a:\n\n```c\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n```\n\nLater, we will use the `size` field for the `sizeof()` operator.\nWe now need to set up both fields when we add a symbol to the global\nor local symbol table.\n\nThe `newsym()` function and all of the `addXX()` functions in `sym.c`\nnow take an `nelems` argument instead of a `size` argument. For scalar\nvariables, this is set to one. For arrays, this is set to the number of\nelements in the list. For functions, this is set to the number of function\nparameters. And for all other symbol tables, the value is unused.\n\nWe now calculate the `size` value in `newsym()`:\n\n```c\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n```\n\n`typesize()` consults the `ctype` pointer to get the size of a struct or\nunion, or calls `genprimsize()` (which calls `cgprimsize()`) to get the\nsize of a pointer or an integer type.\n\nNote the comment about structs and unions. We can't call `addstruct()`\n(which calls `newsym()`) with the details of a struct's size,\nbecause:\n\n```c\nstruct foo {            // We call addglob() here\n  int x;\n  int y;                // before we know the size of the structure\n  int z;\n};\n```\n\nSo the code in `composite_declaration()` in `decl.c` now does this:\n\n```c\nstatic struct symtable *composite_declaration(...) {\n  ...\n  // Build the composite type\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  ...\n  // Scan in the list of members\n  while (1) {\n    ...\n  }\n\n  // Attach to the struct type's node\n  ctype->member = Membhead;\n  ...\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n```\n\nSo, in summary, the `size` field in a symbol table entry now holds\nthe size of all of the elements in the variable, and `nelems` is\nthe count of elements in the variable: one for arrays, some non-zero\npositive number for arrays.\n\n## Array Variable Initialisation\n\nWe can finally get to array initialisation. I want to allow three forms:\n\n```c\nint a[10];                                      // Ten zeroed elements\nchar b[]= { 'q', 'w', 'e', 'r', 't', 'y' };     // Six elements\nchar c[10]= { 'q', 'w', 'e', 'r', 't', 'y' };   // Ten elements, zero padded\n```\n\nbut prevent an array declared with size *N* and more than *N* initialisation\nvalues. Let's look at the changes to `array_declaration()`. Previously,\nI was going to call an `array_initialisation()` function, but I decided to\nmove all of the initialisation code into `array_declaration()` in `decl.c`.\nWe will take it in stages.\n\n```c\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(...) {\n  int nelems= -1;       // Assume the number of elements won't be given\n  ...\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token == T_INTLIT) {\n    if (Token.intvalue <= 0)\n      fatald(\"Array size is illegal\", Token.intvalue);\n    nelems= Token.intvalue;\n    scan(&Token);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n```\n\nIf there's a number between the '[' ']' tokens, parse it and set `nelems`\nto this value. If there is no number, we leave it set to -1 to indicate this.\nWe also check that the number is positive and non-zero.\n\n```c\n    // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n```\n\nRight now I'm only dealing with global arrays.\n\n```c\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems= nelems;\n    else\n      maxelems= TABLE_INCREMENT;\n    initlist= (int *)malloc(maxelems *sizeof(int));\n```\n\nWe create an initial list of either 10 integers, or `nelems` if\nthe array was given a fixed size. However, for arrays with no fixed size,\nwe cannot predict how big the initialisation list will be. So we must be\nprepared to grow the list.\n\n```c\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n        fatal(\"Too many values in initialisation list\");\n      initlist[i++]= parse_literal(type);\n      scan(&Token);\n```\n\nGet the next literal value and ensure we don't have more initial values\nthat the array size if it was specified.\n\n```c\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n        maxelems += TABLE_INCREMENT;\n        initlist= (int *)realloc(initlist, maxelems *sizeof(int));\n      }\n```\n\nHere is where we increase the initialisation list size as necessary.\n\n```c\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n        scan(&Token);\n        break;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n```\n\nParse the closing right curly bracket or a comma that separates values.\nOnce out of the loop, we now have an `initlist` with values in it.\n\n```c\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j=i; j < sym->nelems; j++) initlist[j]=0;\n    if (i > nelems) nelems = i;\n    sym->initlist= initlist;\n  }\n```\n\nWe may not have been given enough initialisation values to meet the\nspecified size of the initialisation list, so zero out all the ones\nthat were not initialised. It is here that we attach the initialisation\nlist to the symbol table entry.\n\n```c\n  // Set the size of the array and the number of elements\n  sym->nelems= nelems;\n  sym->size= sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n  return (sym);\n}\n```\n\nWe can finally updated `nelems` and `size` in the symbol table entry.\nOnce this is done, we can call `genglobsym()` to create the memory\nstorage for the array.\n\n## Changes to `cgglobsym()`\n\nBefore we look at the assembly output of an example array initialisation,\nwe need to see how the changes of `nelems` and `size` have affected the\ncode that generates the assembly for the memory storage.\n\n`genglobsym()` is the front-end function which simply calls `cgglobsym()`.\nLet's look at this function in `cg.c`:\n\n```c\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n```\n\nRight now, arrays have their `type` set to be a pointer to the underlying\nelement type. This allows us to do:\n\n```c\n  char a[45];\n  char *b;\n  b= a;         // as they are of same type\n```\n\nIn terms of generating storage, we need to know the size of the elements,\nso we call `value_at()` to do this. For scalars, `size` and `type` are\nstored as-is in the symbol table entry.\n\n```c\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n```\n\nAs before. But now the code is different:\n\n```c\n  // Output space for one or more elements\n  for (i=0; i < node->nelems; i++) {\n  \n    // Get any initial value\n    initvalue= 0;\n    if (node->initlist != NULL)\n      initvalue= node->initlist[i];\n  \n    // Generate the space for this type\n    switch (size) {\n      case 1:\n        fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal\n        if (node->initlist != NULL && type== pointer_to(P_CHAR))\n          fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++)\n        fprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n```\n\nFor every element, get its intial value from the `initlist` or use zero\nif no initialisation list. Based on the size of each element, output\neither a byte, a long or a quad.\n\nFor `char *` elements, we have the label of the string literal's base\nin the initialisation list, so output \"L%d\" (i.e. the label) instead\nof the integer literal value.\n\n### Array Initialisation Examples\n\nHere is a small example of an array initialisation:\n\n```c\nint x[4]= { 1, 4, 17 };\n```\n\ngenerates:\n\n```\n        .globl  x\nx:\n        .long   1\n        .long   4\n        .long   17\n        .long   0\n```\n\n## Test Programs\n\nI won't go through the test programs, but the programs\n`tests/input89.c` through to `tests/input99.c` check that the\ncompiler is generating sensible initialisation code as well as catching\nsuitable fatal errors.\n\n## Conclusion and What's Next\n\nSo that was a lot of work! Three steps forward and one step back, as\nthey say. I'm happy, though, because the changes to the symbol table\nmake much more sense than what I had before.\n\nIn the next part of our compiler writing journey, we will try to\nadd local variable initialisation to the compiler. [Next step](../41_Local_Var_Init/Readme.md)\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n  \n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i=0; i < node->nelems; i++) {\n  \n    // Get any initial value\n    initvalue= 0;\n    if (node->initlist != NULL)\n      initvalue= node->initlist[i];\n  \n    // Generate the space for this type\n    switch (size) {\n      case 1:\n        fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal\n        if (node->initlist != NULL && type== pointer_to(P_CHAR))\n          fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++)\n  \tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal\n        if (node->initlist != NULL && type == pointer_to(P_CHAR))\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nstatic int parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nstatic int parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Given a type, check that the latest token is a literal\n// of that type. If an integer literal, return this value.\n// If a string literal, return the label number of the string.\n// Do not scan the next token.\nint parse_literal(int type) {\n\n  // We have a string literal. Store in memory and return the label\n  if ((type == pointer_to(P_CHAR)) && (Token.token == T_STRLIT))\n    return(genglobstr(Text));\n\n  if (Token.token == T_INTLIT) {\n    switch(type) {\n      case P_CHAR: if (Token.intvalue < 0 || Token.intvalue > 255)\n\t\t     fatal(\"Integer literal value too big for char type\");\n      case P_INT:\n      case P_LONG: break;\n      default: fatal(\"Type mismatch: integer literal vs. variable\");\n    }\n  } else\n    fatal(\"Expecting an integer literal value\");\n  return(Token.intvalue);\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class) {\n  struct symtable *sym=NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym= addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym= addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym= addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym= addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n      scan(&Token);\n    }\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t// New symbol table entry\n  int nelems= -1;\t// Assume the number of elements won't be given\n  int maxelems;\t\t// The maximum number of elements in the init list\n  int *initlist;\t// The list of initial elements \n  int i=0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token == T_INTLIT) {\n    if (Token.intvalue <= 0)\n      fatald(\"Array size is illegal\", Token.intvalue);\n    nelems= Token.intvalue;\n    scan(&Token);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class,\n\t\t  0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems= nelems;\n    else\n      maxelems= TABLE_INCREMENT;\n    initlist= (int *)malloc(maxelems *sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n        fatal(\"Too many values in initialisation list\");\n      initlist[i++]= parse_literal(type);\n      scan(&Token);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n        maxelems += TABLE_INCREMENT;\n        initlist= (int *)realloc(initlist, maxelems *sizeof(int));\n      }\n\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n        scan(&Token);\n\tbreak;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j=i; j < sym->nelems; j++) initlist[j]=0;\n    if (i > nelems) nelems = i;\n    sym->initlist= initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  sym->nelems= nelems;\n  sym->size= sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, C_GLOBAL, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Generate the assembly code for it\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t= declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE);\n    if (t== -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead==NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->posn = genalign(m->type, offset, 1);\n    else\n      m->posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2) {\n  int inittype, type;\n  struct symtable *sym;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL)\n        fatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nint declaration_list(struct symtable **ctype, int class, int et1, int et2);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n  union {\n    int endlabel;\t\t// For functions, the end label\n    int posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  };\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  union {\t\t\t// the symbol in the symbol table\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken) break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n        tokentype == T_COLON) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs();\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs();\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL) genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      if (n->right != NULL) genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and get the compound expression\n\tmatch(T_COLON, \":\");\n\tleft= compound_statement(1); casecount++;\n\n\t// Build a sub-tree with the compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF);\n      semi();\n      return (NULL);\t\t// No AST generated here\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input31.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input31.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input32.c",
    "content": "Unknown variable:cow on line 4 of input32.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input33.c",
    "content": "Incompatible type to return on line 4 of input33.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input34.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input34.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input35.c",
    "content": "Duplicate local variable declaration:a on line 4 of input35.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input36.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input36.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input37.c",
    "content": "Expected:comma on line 3 of input37.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input38.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input38.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input39.c",
    "content": "No statements in function with non-void type on line 4 of input39.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input40.c",
    "content": "No return for function with non-void type on line 4 of input40.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input41.c",
    "content": "Can't return from a void function on line 3 of input41.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input42.c",
    "content": "Undeclared function:fred on line 3 of input42.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input43.c",
    "content": "Undeclared array:b on line 3 of input43.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input44.c",
    "content": "Unknown variable:z on line 3 of input44.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input45.c",
    "content": "& operator must be followed by an identifier on line 3 of input45.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input46.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input46.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input47.c",
    "content": "++ operator must be followed by an identifier on line 3 of input47.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input48.c",
    "content": "-- operator must be followed by an identifier on line 3 of input48.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input49.c",
    "content": "Incompatible expression in assignment on line 6 of input49.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input50.c",
    "content": "Incompatible types in binary expression on line 6 of input50.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input51.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input51.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input52.c",
    "content": "Unrecognised character:$ on line 5 of input52.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input56.c",
    "content": "unknown struct/union type:var1 on line 2 of input56.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input57.c",
    "content": "previously defined struct/union:fred on line 2 of input57.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input59.c",
    "content": "Undeclared variable:y on line 3 of input59.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input60.c",
    "content": "Undeclared variable:x on line 3 of input60.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input61.c",
    "content": "Undeclared variable:x on line 3 of input61.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input64.c",
    "content": "undeclared enum type::fred on line 1 of input64.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input65.c",
    "content": "enum type redeclared::fred on line 2 of input65.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input66.c",
    "content": "enum value redeclared::z on line 2 of input66.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input68.c",
    "content": "redefinition of typedef:FOO on line 2 of input68.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input69.c",
    "content": "unknown type:FLOO on line 2 of input69.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input72.c",
    "content": "no loop or switch to break out from on line 1 of input72.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input73.c",
    "content": "no loop to continue to on line 1 of input73.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input75.c",
    "content": "Unexpected token in switch:if on line 4 of input75.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input76.c",
    "content": "No cases in switch on line 3 of input76.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input77.c",
    "content": "case or default after existing default on line 6 of input77.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input78.c",
    "content": "case or default after existing default on line 6 of input78.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input79.c",
    "content": "Duplicate case value on line 6 of input79.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input85.c",
    "content": "Bad type in parameter list on line 1 of input85.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input86.c",
    "content": "Function definition not at global level on line 3 of input86.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input87.c",
    "content": "Bad type in member list on line 4 of input87.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input92.c",
    "content": "Integer literal value too big for char type on line 1 of input92.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input93.c",
    "content": "Expecting an integer literal value on line 1 of input93.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input94.c",
    "content": "Type mismatch: integer literal vs. variable on line 1 of input94.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input95.c",
    "content": "Variable can not be initialised:x on line 1 of input95.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input96.c",
    "content": "Array size is illegal:0 on line 1 of input96.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input97.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input97.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/err.input98.c",
    "content": "Too many values in initialisation list on line 1 of input98.c\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input01.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input02.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input03.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input04.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input05.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input06.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input07.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input08.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input09.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input10.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input11.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input12.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input13.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input14.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input15.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input16.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input17.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input18.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input18a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input19.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input20.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input21.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input22.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input23.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input24.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input25.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input26.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input27.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input28.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input29.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input31.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input32.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input33.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input34.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input35.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input36.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input37.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input38.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input39.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input40.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input41.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input42.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input43.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input44.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input45.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input46.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input47.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input48.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input49.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input50.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input51.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input52.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input53.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input54.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input55.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input56.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input57.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input58.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input59.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input60.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input61.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input62.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input63.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input64.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input65.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input66.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input67.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input68.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input69.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input70.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input71.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input72.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input73.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input74.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input75.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input76.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input77.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input78.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input79.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input80.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input81.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input82.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input83.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input84.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input85.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input86.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input87.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input88.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input89.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input90.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input91.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input92.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input93.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input94.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input95.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input96.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input97.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input98.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/input99.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input01.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input02.c",
    "content": "17\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input03.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input04.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input05.c",
    "content": "6\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input06.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input07.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input08.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input09.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input10.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input11.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input12.c",
    "content": "5\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input13.c",
    "content": "23\n56\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input14.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input15.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input16.c",
    "content": "12\n18\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input17.c",
    "content": "19\n12\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input18.c",
    "content": "34\n34\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input18a.c",
    "content": "15\n16\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input19.c",
    "content": "30\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input20.c",
    "content": "12\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input21.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input22.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input23.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input24.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input25.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input26.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input27.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input28.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input29.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input30.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input30.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input53.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input54.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input55.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input58.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input62.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input63.c",
    "content": "25\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input67.c",
    "content": "5\n17\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input70.c",
    "content": "56\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input71.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input74.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input80.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input81.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input82.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input83.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input84.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input88.c",
    "content": "5 6\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input89.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input90.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input91.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/out.input99.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "40_Var_Initialisation_pt2/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\t// XXX Fix soon\n    rsize = typesize(rtype, NULL);\t// XXX Fix soon\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "41_Local_Var_Init/Readme.md",
    "content": "# Part 41: Local Variable Initialisation\n\nWell, after the significant list of changes in the last part, doing local\nvariable initialisation was easy.\n\nWe want to be able to do this sort of thing inside functions:\n\n```c\n  int x= 2, y= x+3, z= 5 * x - y;\n  char *foo= \"Hello world\";\n```\n\nAs we are inside a function, we can build an AST tree for the expression,\nbuild an A_IDENT node for the variable and join them together with an A_ASSIGN parent\nnode. And, because there can be several declarations with assignments, we may need\nto build an A_GLUE tree which holds all of the assignment trees.\n\nThe only wrinkle is that the code which parses local declarations is quite a\ncall distance away from the code that deals with statement parsing. In fact:\n\n + `single_statement()` in `stmt.c` sees a type identifier and calls\n + `declaration_list()` in `decl.c` to parse several declarations, which calls\n + `symbol_declaration()` to parse one declaration, which calls\n + `scalar_declaration()` to parse a scalar variable declaration and assignment\n\nThe main problem is that all of these functions already return a value, so we\ncan't build an AST tree in `scalar_declaration()` and return it back to\n`single_statement()`.\n\nAlso, `declaration_list()` parses multiple declarations, so it will have the job of\nbuilding the A_GLUE tree to hold them all together.\n\nThe solution is to pass down a \"pointer pointer\" from `single_statement()` to\n`declaration_list()`, so that we can pass back the pointer to the A_GLUE tree.\nSimilarly, we will pass a \"pointer pointer\" from `declaration_list()` down to\n`scalar_declaration()`, which will pass back the pointer to any assignment tree\nthat it has built.\n\n## Changes to `scalar_declaration()`\n\nIf we are in local context and we hit an '=' in a scalar variable's declaration,\nhere is what we do:\n\n```c\n  struct ASTnode *varnode, *exprnode;\n  struct ASTnode **tree;                 // is the ptr ptr argument that we get passed\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    ...\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, 0);\n      if (exprnode == NULL)\n        fatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode,\n                                        NULL, varnode, NULL, 0);\n    }\n  }\n```\n\nThat's it. We simulate the AST tree building that would normally occur in `expr.c` for\nan assignment expression. Once done, we pass back the assignment tree. This\nbubbles back up to `declaration_list()`. It now does:\n\n```c\n  struct ASTnode **gluetree;            // is the ptr ptr argument that we get passed\n  struct ASTnode *tree;\n  *gluetree= NULL;\n  ...\n  // Now parse the list of symbols\n  while (1) {\n    ...\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n    ...\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree== NULL)\n      *gluetree= tree;\n    else\n      *gluetree = mkastnode(A_GLUE, P_NONE, *gluetree, NULL, tree, NULL, 0);\n    ...\n  }\n```\n\nSo `gluetree` is set to the AST tree with a bunch of A_GLUE nodes, each of which\nhas an A_ASSIGN child with an A_IDENT child and an expression child.\n\nAnd, way up in `single_statement()` in `stmt.c`:\n\n```c\n    ...\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n        stmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);            // Any assignments from the declarations\n    ...\n```\n\n## Testing the New Code\n\nThe above changes were so short and simple that they compiled and worked first time.\nThis is not a regular occurrence! Our test program, `tests/input100.c` is this:\n\n```c\n#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n```\n\nand produces the following correct output: `Hello world 17 20`.\n\n## Conclusion and What's Next\n\nIt's nice to have a simple part on this journey now and then. I'm now starting to\ntake wagers with myself as to:\n\n + how many parts to the journey, in total, there will be, and\n + will I get it all done by the end of the year\n\nRight now I'm guessing about 60 parts and an 75% chance of completing by year's end.\nBut we still have a bunch of small, but possibly difficult, features to add to the\ncompiler.\n\nIn the next part of our compiler writing journey, I will add cast parsing to the compiler. [Next step](../42_Casting/Readme.md)\n"
  },
  {
    "path": "41_Local_Var_Init/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n  \n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i=0; i < node->nelems; i++) {\n  \n    // Get any initial value\n    initvalue= 0;\n    if (node->initlist != NULL)\n      initvalue= node->initlist[i];\n  \n    // Generate the space for this type\n    switch (size) {\n      case 1:\n        fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal\n        if (node->initlist != NULL && type== pointer_to(P_CHAR))\n          fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++)\n  \tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "41_Local_Var_Init/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:     fatald(\"Bad type in calc_aligned_offset:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal\n        if (node->initlist != NULL && type == pointer_to(P_CHAR))\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "41_Local_Var_Init/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "41_Local_Var_Init/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nstatic int parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nstatic int parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Given a type, check that the latest token is a literal\n// of that type. If an integer literal, return this value.\n// If a string literal, return the label number of the string.\n// Do not scan the next token.\nint parse_literal(int type) {\n\n  // We have a string literal. Store in memory and return the label\n  if ((type == pointer_to(P_CHAR)) && (Token.token == T_STRLIT))\n    return(genglobstr(Text));\n\n  if (Token.token == T_INTLIT) {\n    switch(type) {\n      case P_CHAR: if (Token.intvalue < 0 || Token.intvalue > 255)\n\t\t     fatal(\"Integer literal value too big for char type\");\n      case P_INT:\n      case P_LONG: break;\n      default: fatal(\"Type mismatch: integer literal vs. variable\");\n    }\n  } else\n    fatal(\"Expecting an integer literal value\");\n  return(Token.intvalue);\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym=NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree= NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym= addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym= addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym= addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym= addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n      scan(&Token);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, 0);\n      if (exprnode == NULL)\n        fatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode,\n\t\t\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t// New symbol table entry\n  int nelems= -1;\t// Assume the number of elements won't be given\n  int maxelems;\t\t// The maximum number of elements in the init list\n  int *initlist;\t// The list of initial elements \n  int i=0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token == T_INTLIT) {\n    if (Token.intvalue <= 0)\n      fatald(\"Array size is illegal\", Token.intvalue);\n    nelems= Token.intvalue;\n    scan(&Token);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class,\n\t\t  0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems= nelems;\n    else\n      maxelems= TABLE_INCREMENT;\n    initlist= (int *)malloc(maxelems *sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n        fatal(\"Too many values in initialisation list\");\n      initlist[i++]= parse_literal(type);\n      scan(&Token);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n        maxelems += TABLE_INCREMENT;\n        initlist= (int *)realloc(initlist, maxelems *sizeof(int));\n      }\n\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n        scan(&Token);\n\tbreak;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j=i; j < sym->nelems; j++) initlist[j]=0;\n    if (i > nelems) nelems = i;\n    sym->initlist= initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  sym->nelems= nelems;\n  sym->size= sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, C_GLOBAL, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Generate the assembly code for it\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t= declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t== -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead==NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->posn = genalign(m->type, offset, 1);\n    else\n      m->posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree= NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL)\n        fatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree== NULL)\n      *gluetree= tree;\n    else\n      *gluetree = mkastnode(A_GLUE, P_NONE, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "41_Local_Var_Init/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n  union {\n    int endlabel;\t\t// For functions, the end label\n    int posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  };\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  union {\t\t\t// the symbol in the symbol table\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "41_Local_Var_Init/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken) break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    // Scan in the expression and the right parenthesis\n    scan(&Token);\n    n = binexpr(0);\n    rparen();\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n        tokentype == T_COLON) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs();\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs();\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL) genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      if (n->right != NULL) genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "41_Local_Var_Init/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "41_Local_Var_Init/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "41_Local_Var_Init/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "41_Local_Var_Init/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and get the compound expression\n\tmatch(T_COLON, \":\");\n\tleft= compound_statement(1); casecount++;\n\n\t// Build a sub-tree with the compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input032.c",
    "content": "Unknown variable:cow on line 4 of input032.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input042.c",
    "content": "Undeclared function:fred on line 3 of input042.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input043.c",
    "content": "Undeclared array:b on line 3 of input043.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input044.c",
    "content": "Unknown variable:z on line 3 of input044.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input059.c",
    "content": "Undeclared variable:y on line 3 of input059.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input060.c",
    "content": "Undeclared variable:x on line 3 of input060.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input061.c",
    "content": "Undeclared variable:x on line 3 of input061.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input092.c",
    "content": "Integer literal value too big for char type on line 1 of input092.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input093.c",
    "content": "Expecting an integer literal value on line 1 of input093.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input094.c",
    "content": "Type mismatch: integer literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "41_Local_Var_Init/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "41_Local_Var_Init/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "41_Local_Var_Init/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "41_Local_Var_Init/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "41_Local_Var_Init/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\t// XXX Fix soon\n    rsize = typesize(rtype, NULL);\t// XXX Fix soon\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n  // For pointers on the left\n  if (ptrtype(ltype)) {\n    // OK is same type on right and not doing a binary op\n    if (op == 0 && ltype == rtype)\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "42_Casting/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "42_Casting/Readme.md",
    "content": "# Part 42: Type Casting and NULL\n\nIn this part of our compiler writing journey, I've implemented type casting.\nI thought this would allow me to do:\n\n```c\n#define NULL (void *)0\n```\n\nbut I hadn't done enough to get `void *` to work properly. So I've added\ntype casting and also got `void *` to work.\n\n## What is Type Casting?\n\nType casting is where you forcibly change the type of an expression to\nbe something else. Common reasons are to narrow an integer value down\nto a smaller range type, or to assign a pointer from one type into\na pointer storage of another type, e.g.\n\n```c\n  int   x= 65535;\n  char  y= (char)x;     // y is now 255, the lower 8 bits\n  int  *a= &x;\n  char *b= (char *)a;   // b point at the address of x\n  long *z= (void *)0;   // z is a NULL pointer, not pointing at anything\n```\n\nNotice above that I've used the casts in assignment statements. For\nexpressions within functions, we will need to add an A_CAST node to our\nAST tree to say \"cast the original expression type to this new type\".\n\nFor global variable assignments, we will need to modify the assignment\nparser to allow a cast to come before the literal value.\n\n## A New Function, `parse_cast()`\n\nI've added this new function in `decl.c`:\n\n```c\n// Parse a type which appears inside a cast\nint parse_cast(void) {\n  int type, class;\n  struct symtable *ctype;\n\n  // Get the type inside the parentheses\n  type= parse_stars(parse_type(&ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return(type);\n}\n```\n\nThe parsing of the surrounding '(' ... ')' is done elsewhere. We get the\ntype identifier and the following '*' tokens to get the type of the cast.\nThen we prevent casts to structs, unions and to `void`.\n\nWe need a function to do this as we have to do it in expressions and also\nin global variable assignments. I didn't want any\n[DRY code](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself).\n\n## Cast Parsing in Expressions\n\nWe already parse parentheses in our expression code, so we will need to\nmodify this. In `primary()` in `expr.c`, we now do this:\n\n```c\nstatic struct ASTnode *primary(void) {\n  int type=0;\n  ...\n  switch (Token.token) {\n  ...\n    case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    scan(&Token);\n\n\n    // If the token after is a type identifier, this is a cast expression\n    switch (Token.token) {\n      case T_IDENT:\n        // We have to see if the identifier matches a typedef.\n        // If not, treat it as an expression.\n        if (findtypedef(Text) == NULL) {\n          n = binexpr(0); break;\n        }\n      case T_VOID:\n      case T_CHAR:\n      case T_INT:\n      case T_LONG:\n      case T_STRUCT:\n      case T_UNION:\n      case T_ENUM:\n        // Get the type inside the parentheses\n        type= parse_cast();\n\n        // Skip the closing ')' and then parse the following expression\n        rparen();\n\n      default: n = binexpr(0); // Scan in the expression\n    }\n\n    // We now have at least an expression in n, and possibly a non-zero type in type\n    // if there was a cast. Skip the closing ')' if there was no cast.\n    if (type == 0)\n      rparen();\n    else\n      // Otherwise, make a unary AST node for the cast\n      n= mkastunary(A_CAST, type, n, NULL, 0);\n    return (n);\n  }\n}\n```\n\nThat's a lot to digest, so let's go through it in stages. All of the cases\nensure that we have a type identifier after the '(' token. We call `parse_cast()`\nto get the cast type and parse the ')' token.\n\nWe don't have an AST tree to return yet because we don't know which expression\nwe are casting. So we fall through to the default case where the next expression\nis parsed.\n\nAt this point either `type` is still zero (no cast) or non-zero (there was a cast).\nIf no cast, the right parenthesis has to be skipped and we can simply return\nthe expression in parentheses.\n\nIf there was a cast, we build an A_CAST node with the new `type` and with the\nfollowing expression as the child.\n\n## Generating the Assembly Code for a Cast\n\nWell, we are lucky because the expression's value will be stored in a register.\nSo if we do:\n\n```c\n  int   x= 65535;\n  char  y= (char)x;     // y is now 255, the lower 8 bits\n```\n\nthen we can simply put the 65535 into a register. But when we\nsave it to y, then the lvalue's type will be invoked to generate\nthe correct code to save the right size:\n\n```\n        movq    $65535, %r10            # Store 65535 in x\n        movl    %r10d, -4(%rbp)\n        movslq  -4(%rbp), %r10          # Get x into %r10\n        movb    %r10b, -8(%rbp)         # Store one byte into y\n```\n\nSo, in `genAST()` in `gen.c`, we have this code to deal with casting:\n\n```c\n  ...\n  leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  ...\n  switch (n->op) {\n    ...\n    case A_CAST:\n      return (leftreg);         // Not much to do\n    ...\n  }\n```\n\n## Casts in Global Assignments\n\nThe above is fine when the variables are local variables,\nas the compiler does the above assignments as expressions.\nFor global variables, we have to hand-parse the cast\nand apply it to a literal value that follows it.\n\nSo, for example, in `scalar_declaration` in `decl.c` we need\nthis code:\n\n```c\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL) {\n      // If there is a cast\n      if (Token.token == T_LPAREN) {\n        // Get the type in the cast\n        scan(&Token);\n        casttype= parse_cast();\n        rparen();\n\n        // Check that the two types are compatible. Change\n        // the new type so that the literal parse below works.\n        // A 'void *' casstype can be assigned to any pointer type.\n        if (casttype == type || (casttype== pointer_to(P_VOID) && ptrtype(type)))\n          type= P_NONE;\n        else\n          fatal(\"Type mismatch\");\n      }\n\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n      scan(&Token);\n    }\n```\n \nFirst of all, note that we set `type= P_NONE` when there is a cast,\nand we call `parse_literal()` with P_NONE when there is a cast. Why?\nBecause this function used to required that the literal being parsed\nwas exactly the type which was the argument, i.e. a string literal\nhad to be of type `char *`, a `char` had to be matched by a literal\nin the range 0 ... 255 etc.\n\nNow that we have a cast, we should be able to accept:\n\n```c\n  char a= (char)65536;\n```\n\nSo the code in `parse_literal()` in `decl.c` now does this:\n\n```c\nint parse_literal(int type) {\n\n  // We have a string literal. Store in memory and return the label\n  if (Token.token == T_STRLIT) {\n    if (type == pointer_to(P_CHAR) || type == P_NONE)\n    return(genglobstr(Text));\n  }\n\n  // We have an integer literal. Do some range checking.\n  if (Token.token == T_INTLIT) {\n    switch(type) {\n      case P_CHAR: if (Token.intvalue < 0 || Token.intvalue > 255)\n                     fatal(\"Integer literal value too big for char type\");\n      case P_NONE:\n      case P_INT:\n      case P_LONG: break;\n      default: fatal(\"Type mismatch: integer literal vs. variable\");\n    }\n  } else\n    fatal(\"Expecting an integer literal value\");\n  return(Token.intvalue);\n}\n```\n\nand the P_NONE is used to relax the type restrictions.\n\n## Dealing with `void *`\n\nA `void *` pointer is one that can be used in place of any other\npointer type. So we have to implement this.\n\nWe already did this for global variable assignments above:\n\n```c\n   if (casttype == type || (casttype== pointer_to(P_VOID) && ptrtype(type)))\n```\n\ni.e. if the types are equal, or if a `void *` pointer is being assigned\nto a pointer. This allows the following global assignment:\n\n```c\n  char *str= (void *)0;\n```\n\neven though `str` is of type `char *` and not `void *`.\n\nNow we need to deal with `void *` (and other pointer/pointer operations)\nin expressions. To do this, I had to change `modify_type()` in `types.c`.\nAs a refresher, here is what this function does:\n\n```c\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n```\n\nThis is the code that widens values, e.g. `int x= 'Q';` to make `x` into\na 32-bit value. We also use it for scaling: when we do:\n\n```c\n  int x[4];\n  int y= x[2];\n```\n\nThe \"2\" index is scaled by the size of `int` to be eight bytes offset from\nthe base of the `x[]` array.\n\nSo, inside a function, when we write:\n\n```c\n  char *str= (void *)0;\n```\n\nwe get the AST tree:\n\n```\n          A_ASSIGN\n           /    \\\n       A_CAST  A_IDENT\n         /      str\n     A_INTLIT\n         0\n```\n  \nthe type of the left-hand `tree` will be `void *` and the `rtype` will be\n`char *`. We had better ensure that the operation can be performed.\n\nI've changed `modify_type()` to do this for pointers:\n\n```c\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return(tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n```\n\nNow, pointer comparison is OK but other binary operations (e.g. addition) is bad.\nA \"non-binary operation\" means something like an assignment. We can definitely\nassign between two things of the same type. Now, we can also assign from a `void *`\npointer to any pointer.\n\n## Adding NULL\n\nNow that we can deal with `void *` pointers, we can add NULL to our include files.\nI've added this to both `stdio.h` and `stddef.h`:\n\n```c\n#ifndef NULL\n# define NULL (void *)0\n#endif\n```\n\nBut there was one final wrinkle. When I tried this global declaration:\n\n```c\n#include <stdio.h>\nchar *str= NULL;\n```\n\nI got this:\n\n```\nstr:\n        .quad   L0\n```\n\nbecause every initialisation value for a `char *` pointer is\ntreated as a label number. So the \"0\" in the NULL was being turned\ninto an \"L0\" label. We need to fix this. Now, in `cgglobsym()`\nin `cg.c`:\n\n```c\n      case 8:\n        // Generate the pointer to a string literal. Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type== pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n```\n\nYes it's ugly but it works!\n\n## Testing the Changes\n\nI won't go through all the tests themselves, but files\n`tests/input101.c` to `tests/input108.c` test the above\nfunctionality and also the error checking of the compiler.\n\n## Conclusion and What's Next\n\nI thought casting was going to be easy, and it was. What I didn't\nreckon with was the issues surrounding `void *`. I feel that I've\ncovered most bases here but not all of them, so expect to see\nsome `void *` edge cases that I haven't spotted yet.\n\nIn the next part of our compiler writing journey, we'll add some missing\noperators. [Next step](../43_More_Operators/Readme.md)\n"
  },
  {
    "path": "42_Casting/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n  \n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i=0; i < node->nelems; i++) {\n  \n    // Get any initial value\n    initvalue= 0;\n    if (node->initlist != NULL)\n      initvalue= node->initlist[i];\n  \n    // Generate the space for this type\n    switch (size) {\n      case 1:\n        fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n        if (node->initlist != NULL && type== pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++)\n  \tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "42_Casting/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "42_Casting/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "42_Casting/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "42_Casting/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(void) {\n  int type, class;\n  struct symtable *ctype;\n\n  // Get the type inside the parentheses\n  type= parse_stars(parse_type(&ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return(type);\n}\n\n// Given a type, check that the latest token is a literal\n// of that type. If an integer literal, return this value.\n// If a string literal, return the label number of the string.\n// Do not scan the next token. If type is P_NONE, relax all\n// parse restrictions\nint parse_literal(int type) {\n\n  // We have a string literal. Store in memory and return the label\n  if (Token.token == T_STRLIT) {\n    if (type == pointer_to(P_CHAR) || type == P_NONE)\n    return(genglobstr(Text));\n  }\n\n  // We have an integer literal. Do some range checking.\n  if (Token.token == T_INTLIT) {\n    switch(type) {\n      case P_CHAR: if (Token.intvalue < 0 || Token.intvalue > 255)\n\t\t     fatal(\"Integer literal value too big for char type\");\n      case P_NONE:\n      case P_INT:\n      case P_LONG: break;\n      default: fatal(\"Type mismatch: integer literal vs. variable\");\n    }\n  } else\n    fatal(\"Expecting an integer literal value\");\n  return(Token.intvalue);\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym=NULL;\n  struct ASTnode *varnode, *exprnode;\n  int casttype;\n  *tree= NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym= addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym= addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym= addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym= addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL) {\n      // If there is a cast\n      if (Token.token == T_LPAREN) {\n\t// Get the type in the cast\n        scan(&Token);\n        casttype= parse_cast();\n\trparen();\n\n\t// Check that the two types are compatible. Change\n\t// the new type so that the literal parse below works.\n\t// A 'void *' casstype can be assigned to any pointer type.\n\tif (casttype == type || (casttype== pointer_to(P_VOID) && ptrtype(type)))\n\t  type= P_NONE;\n\telse\n\t  fatal(\"Type mismatch\");\n      }\n\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n      scan(&Token);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, 0);\n      if (exprnode == NULL)\n        fatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode,\n\t\t\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t// New symbol table entry\n  int nelems= -1;\t// Assume the number of elements won't be given\n  int maxelems;\t\t// The maximum number of elements in the init list\n  int *initlist;\t// The list of initial elements \n  int i=0, j;\n  int casttype, newtype;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token == T_INTLIT) {\n    if (Token.intvalue <= 0)\n      fatald(\"Array size is illegal\", Token.intvalue);\n    nelems= Token.intvalue;\n    scan(&Token);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class,\n\t\t  0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems= nelems;\n    else\n      maxelems= TABLE_INCREMENT;\n    initlist= (int *)malloc(maxelems *sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n      // Get the original type\n      newtype= type;\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n        fatal(\"Too many values in initialisation list\");\n\n      if (Token.token == T_LPAREN) {\n\t// Get the type in the cast\n        scan(&Token);\n        casttype= parse_cast();\n\trparen();\n\n\t// Check that the two types are compatible. Change\n\t// the new type so that the literal parse below works.\n\t// A 'void *' casstype can be assigned to any pointer type.\n\tif (casttype == type || (casttype== pointer_to(P_VOID) && ptrtype(type)))\n\t  newtype= P_NONE;\n\telse\n\t  fatal(\"Type mismatch\");\n\tnewtype= P_NONE;\n      }\n\n      initlist[i++]= parse_literal(newtype);\n      scan(&Token);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n        maxelems += TABLE_INCREMENT;\n        initlist= (int *)realloc(initlist, maxelems *sizeof(int));\n      }\n\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n        scan(&Token);\n\tbreak;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j=i; j < sym->nelems; j++) initlist[j]=0;\n    if (i > nelems) nelems = i;\n    sym->initlist= initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  sym->nelems= nelems;\n  sym->size= sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, C_GLOBAL, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Generate the assembly code for it\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t= declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t== -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead==NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->posn = genalign(m->type, offset, 1);\n    else\n      m->posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name= NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree= NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL)\n        fatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree== NULL)\n      *gluetree= tree;\n    else\n      *gluetree = mkastnode(A_GLUE, P_NONE, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "42_Casting/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(void);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "42_Casting/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n  union {\n    int endlabel;\t\t// For functions, the end label\n    int posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  };\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  union {\t\t\t// the symbol in the symbol table\n    int intvalue;\t\t// For A_INTLIT, the integer value\n    int size;\t\t\t// For A_SCALE, the size to scale by\n  };\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "42_Casting/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken) break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n  int type=0;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    scan(&Token);\n\n\n    // If the token after is a type identifier, this is a cast expression\n    switch (Token.token) {\n      case T_IDENT:\n        // We have to see if the identifier matches a typedef.\n        // If not, treat it as an expression.\n        if (findtypedef(Text) == NULL) {\n          n = binexpr(0); break;\n        }\n      case T_VOID:\n      case T_CHAR:\n      case T_INT:\n      case T_LONG:\n      case T_STRUCT:\n      case T_UNION:\n      case T_ENUM:\n\t// Get the type inside the parentheses\n        type= parse_cast();\n        // Skip the closing ')' and then parse the following expression\n        rparen();\n\n      default: n = binexpr(0); // Scan in the expression\n    }\n\n    // We now have at least an expression in n, and possibly a non-zero type in type\n    // if there was a cast. Skip the closing ')' if there was no cast.\n    if (type == 0)\n      rparen();\n    else\n      // Otherwise, make a unary AST node for the cast\n      n= mkastunary(A_CAST, type, n, NULL, 0);\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype == T_ASSIGN)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 20, 30,\t\t// T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n        tokentype == T_COLON) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "42_Casting/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs();\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs();\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL) genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      if (n->right != NULL) genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASSIGN:\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (leftreg);\t\t// Not much to do\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "42_Casting/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "42_Casting/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "42_Casting/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "42_Casting/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "42_Casting/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "42_Casting/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "42_Casting/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "42_Casting/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "42_Casting/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "42_Casting/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      t->token = T_STAR;\n      break;\n    case '/':\n      t->token = T_SLASH;\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "42_Casting/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and get the compound expression\n\tmatch(T_COLON, \":\");\n\tleft= compound_statement(1); casecount++;\n\n\t// Build a sub-tree with the compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "42_Casting/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "42_Casting/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "42_Casting/tests/err.input032.c",
    "content": "Unknown variable:cow on line 4 of input032.c\n"
  },
  {
    "path": "42_Casting/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "42_Casting/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "42_Casting/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "42_Casting/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "42_Casting/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "42_Casting/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "42_Casting/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "42_Casting/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "42_Casting/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "42_Casting/tests/err.input042.c",
    "content": "Undeclared function:fred on line 3 of input042.c\n"
  },
  {
    "path": "42_Casting/tests/err.input043.c",
    "content": "Undeclared array:b on line 3 of input043.c\n"
  },
  {
    "path": "42_Casting/tests/err.input044.c",
    "content": "Unknown variable:z on line 3 of input044.c\n"
  },
  {
    "path": "42_Casting/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "42_Casting/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "42_Casting/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "42_Casting/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "42_Casting/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "42_Casting/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "42_Casting/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "42_Casting/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "42_Casting/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "42_Casting/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "42_Casting/tests/err.input059.c",
    "content": "Undeclared variable:y on line 3 of input059.c\n"
  },
  {
    "path": "42_Casting/tests/err.input060.c",
    "content": "Undeclared variable:x on line 3 of input060.c\n"
  },
  {
    "path": "42_Casting/tests/err.input061.c",
    "content": "Undeclared variable:x on line 3 of input061.c\n"
  },
  {
    "path": "42_Casting/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "42_Casting/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "42_Casting/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "42_Casting/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "42_Casting/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "42_Casting/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "42_Casting/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "42_Casting/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "42_Casting/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "42_Casting/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "42_Casting/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "42_Casting/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "42_Casting/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "42_Casting/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "42_Casting/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "42_Casting/tests/err.input092.c",
    "content": "Integer literal value too big for char type on line 1 of input092.c\n"
  },
  {
    "path": "42_Casting/tests/err.input093.c",
    "content": "Expecting an integer literal value on line 1 of input093.c\n"
  },
  {
    "path": "42_Casting/tests/err.input094.c",
    "content": "Type mismatch: integer literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "42_Casting/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "42_Casting/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "42_Casting/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "42_Casting/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "42_Casting/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "42_Casting/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "42_Casting/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "42_Casting/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "42_Casting/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "42_Casting/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "42_Casting/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "42_Casting/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "42_Casting/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "42_Casting/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "42_Casting/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "42_Casting/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "42_Casting/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "42_Casting/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "42_Casting/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "42_Casting/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "42_Casting/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "42_Casting/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "42_Casting/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "42_Casting/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "42_Casting/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "42_Casting/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "42_Casting/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "42_Casting/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "42_Casting/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "42_Casting/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "42_Casting/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "42_Casting/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "42_Casting/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "42_Casting/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "42_Casting/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "42_Casting/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "42_Casting/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "42_Casting/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "42_Casting/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "42_Casting/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "42_Casting/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "42_Casting/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "42_Casting/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "42_Casting/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "42_Casting/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "42_Casting/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "42_Casting/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "42_Casting/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "42_Casting/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "42_Casting/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "42_Casting/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "42_Casting/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "42_Casting/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "42_Casting/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "42_Casting/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "42_Casting/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "42_Casting/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "42_Casting/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "42_Casting/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "42_Casting/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "42_Casting/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "42_Casting/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "42_Casting/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "42_Casting/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "42_Casting/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "42_Casting/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "42_Casting/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "42_Casting/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "42_Casting/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "42_Casting/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "42_Casting/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "42_Casting/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "42_Casting/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "42_Casting/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "42_Casting/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "42_Casting/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "42_Casting/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "42_Casting/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "42_Casting/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "42_Casting/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "42_Casting/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "42_Casting/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "42_Casting/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "42_Casting/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "42_Casting/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "42_Casting/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "42_Casting/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "42_Casting/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "42_Casting/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "42_Casting/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "42_Casting/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "42_Casting/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "42_Casting/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "42_Casting/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "42_Casting/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "42_Casting/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "42_Casting/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "42_Casting/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "42_Casting/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "42_Casting/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "42_Casting/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "42_Casting/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "42_Casting/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "42_Casting/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "42_Casting/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "42_Casting/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "42_Casting/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "42_Casting/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "42_Casting/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "42_Casting/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "42_Casting/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "42_Casting/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "42_Casting/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "42_Casting/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "42_Casting/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "42_Casting/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "42_Casting/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "42_Casting/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "42_Casting/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "42_Casting/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "42_Casting/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "42_Casting/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "42_Casting/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "42_Casting/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "42_Casting/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "42_Casting/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "42_Casting/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "42_Casting/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "42_Casting/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "42_Casting/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "42_Casting/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "42_Casting/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "42_Casting/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "42_Casting/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return(tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "43_More_Operators/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\tscan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "43_More_Operators/Readme.md",
    "content": "# Part 43: Bugfixes and More Operators\n\nI've started to pass some of the source code of our compiler as input to itself,\nas this is how we are going to get it to eventually compile itself. The\nfirst big hurdle is to get the compiler to parse and recognise its source code.\nThe second big hurdle will be to get the compiler to generate correct, working,\ncode from its source code.\n\nThis is also the first time that the compiler has been given some substantial\ninput to chew on, and it's going to reveal a bunch of bugs, misfeatures and\nmissing features.\n\n## Bugfixes\n\nI started with `cwj -S defs.h` and found several header files missing. For now\nthey exist but are empty. With these in place, the compiler crashes with a\nsegfault. I had a few pointers which should be initialised to NULL and places\nwhere I wasn't checking for a NULL pointer.\n\n## Missing Features\n\nNext up, I hit `enum { NOREG = -1 ...` in `defs.h` and realised that the\nscanner wasn't dealing with integer literals which start with a minus sign.\nSo I've added this code to `scan()` in `scan.c`:\n\n```c\n    case '-':\n      if ((c = next()) == '-') {\n        t->token = T_DEC;\n      } else if (c == '>') {\n        t->token = T_ARROW;\n      } else if (isdigit(c)) {          // Negative int literal\n        t->intvalue = -scanint(c);\n        t->token = T_INTLIT;\n      } else {\n        putback(c);\n        t->token = T_MINUS;\n      }\n```\n\nIf a '-' is followed by a digit, scan in the integer literal and negate its\nvalue. At first I was worried that the expression `1 - 1` would be treated\nas the two tokens '1', 'int literal -1', but I forgot that `next()` doesn't\nskip the space. So, by having a space between the '-' and the '1', the\nexpression `1 - 1` is correctly parsed as '1', '-', '1'.\n\nHowever, as [Luke Gruber](https://github.com/luke-gru) has pointed out,\nthis also means that the input `1-1` **is** treated as `1 -1` instead of\n`1 - 1`. In other words, the scanner is too greedy and forces `-1` to\nalways be treated as a T_INTLIT when sometimes it shouldn't be. I'm going\nto leave this for now, as we can work around it when writing our source\ncode. Obviously, in a production compiler this would have to be fixed.\n\n## Misfeatures\n\nIn the AST node and symbol table node structures, I've been using unions to\ntry and keep the size of each node down. I guess I'm a bit old school and\nI worry about wasting memory. An example is the AST node structure:\n\n```c\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  ...\n  union {                       // the symbol in the symbol table\n    int intvalue;               // For A_INTLIT, the integer value\n    int size;                   // For A_SCALE, the size to scale by\n  };\n};\n```\n\nBut the compiler isn't able to parse and work with a union inside a struct,\nand especially an unnamed union inside a struct. I could add this functionality,\nbut it will be easier to redo the two structs where I do this. So, I've\nmade these changes:\n\n```c\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  ...\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  ...\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  ...\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n```\n\nThis way, I still have two named fields sharing the same location in each\nstruct, but the compiler will see only the one field name in each struct.\nI've given each `#define` a different prefix to prevent pollution of the\nglobal namespace.\n\nA consequence of this is that I've had to rename the `endlabel`, `posn`,\n`intvalue` and `size` fields across half a dozen source files. C'est la vie.\n\nSo now the compiler, when doing `cwj -S misc.c` gets up to:\n\n```\nExpected:] on line 16 of data.h, where the line is\nextern char Text[TEXTLEN + 1];\n```\n\nThis fails as the compiler as it stands does not parse expressions in a\nglobal variable declaration. I'm going to have to rethink this.\n\nMy thoughts so far are to use `binexpr()` to parse the expression,\nand to add some optimisation code to perform\n[constant folding](https://en.wikipedia.org/wiki/Constant_folding)\non the resulting AST tree. This should result in a single A_INTLIT node\nfrom which I can extract the literal value. I could even let `binexpr()`\nparse any casts, e.g.\n\n```c\n char x= (char)('a' + 1024);\n```\n\nAnyway, that's something for the future. I was going to do constant folding\nat some point, but I thought it would be further down the track.\n\nWhat I will do in this part of the journey is add some more operators:\nspecifically, '+=', '-=', '*=' and '/='. We currently use the first two operators\nin the compiler's source code.\n\n## New Tokens, Scanning and Parsing\n\nAdding new keywords to our compiler is easy: a new token and a change to the\nscanner. Adding new operators is much harder as we have to:\n\n  + align the token with the AST operation\n  + deal with precedence and associativity.\n\nWe are adding four operators: '+=', '-=', '*=' and '/='. They have matching\ntokens: T_ASPLUS, T_ASMINUS, T_ASSTAR and T_ASSLASH. These have\ncorresponding AST operations: A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH. The AST operations **must** have the same enum value as the tokens\nbecause of this function in `expr.c`:\n\n```c\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);                   // Keep -Wall happy\n}\n```\n\nWe also need to configure the precedence of the new operators.\nAccording to [this list of C operators](https://en.cppreference.com/w/c/language/operator_precedence), these new operators have the same precedence as\nour existing assignment operator, so we can modify the `OpPrec[]` table in\n`expr.c` as follows:\n\n```c\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,                    // T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,                   // T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  20, 30,                       // T_LOGOR, T_LOGAND\n  ...\n};\n```\n\nBut that list of C operators also notes that the assignment operators are\n*right_associative*. This means, for example, that:\n\n```c\n   a += b + c;          // needs to be parsed as\n   a += (b + c);        // not\n   (a += b) + c;\n```\n\nSo we also need to update this function in `expr.c` to do this:\n\n```c\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n```\n\nFortunately, these are the only changes we need to make to our scanner\nand expression parser: the Pratt parser for binary expressions is now\nprimed to deal with the new operators.\n\n## Dealing with the AST Tree\n\nNow that we can parse expressions with the four new operators, we need to\ndeal with the AST that is created for each expression. One thing we need to\ndo is dump the AST tree. So, in `dumpAST()` in `tree.c`, I added this code:\n\n```c\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\"); return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\"); return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\"); return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\"); return;\n```\n\nNow when I run `cwj -T input.c` with the expression `a += b + c`, I see:\n\n```\n  A_IDENT rval a\n    A_IDENT rval b\n    A_IDENT rval c\n  A_ADD\nA_ASPLUS\n```\n\nwhich we can redraw as:\n\n```\n          A_ASPLUS\n         /        \\\n     A_IDENT     A_ADD\n     rval a     /     \\\n            A_IDENT  A_IDENT\n             rval b  rval c\n```\n\n## Generating the Assembly For the Operators\n\nWell, in `gen.c` we already walk the AST tree and deal with A_ADD and A_ASSIGN.\nIs there a way to use the existing code to make implementing the new A_ASPLUS\noperator a bit easier? Yes!\n\nWe can rewrite the above AST tree to look like this:\n\n```\n                A_ASSIGN\n               /       \\\n            A_ADD      lval a\n         /        \\\n     A_IDENT     A_ADD\n     rval a     /     \\\n            A_IDENT   A_IDENT\n             rval b   rval c\n```\n\nNow, we don't *have* to rewrite the tree as long as we perform the tree walking\n*as if* the tree had been rewritten like this.\n\nSo in `genAST()`, we have:\n\n```c\nint genAST(...) {\n  ...\n  // Get the left and right sub-tree values. This code already here.\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n}\n```\n\nFrom the perspective of doing the work for the A_ASPLUS node, we have\nevaluated the left-hand child (e.g. `a`'s value) and the right-hand child\n(e.g. `b+c`) and we have the values in two registers. If this was an A_ADD\noperation, we would `cgadd(leftreg, rightreg)` at this point. Well, it is\nan A_ADD operation on these children, then followed by an assignment back into `a`.\n\nSo, the `genAST()` code now has this:\n\n```c\n  switch (n->op) {\n    ... \n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n        case A_ASPLUS:\n          leftreg= cgadd(leftreg, rightreg);\n          n->right= n->left;\n          break;\n        case A_ASMINUS:\n          leftreg= cgsub(leftreg, rightreg);\n          n->right= n->left;\n          break;\n        case A_ASSTAR:\n          leftreg= cgmul(leftreg, rightreg);\n          n->right= n->left;\n          break;\n        case A_ASSLASH:\n          leftreg= cgdiv(leftreg, rightreg);\n          n->right= n->left;\n          break;\n      }\n\n      // And the existing code to do A_ASSIGN is here\n     ...\n  }\n```\n\nIn other words, for each new operator, we perform the correct maths operation\non the children. But before we can drop into the A_ASSIGN we have to move\nthe left-child pointer over to be the right child. Why? Because the A_ASSIGN\ncode expects the destination to be the right child:\n\n```c\n      return (cgstorlocal(leftreg, n->right->sym));\n```\n\nAnd that's it. We were lucky to have code which we could adapt to add in these four new\noperators. There are more assignment operators which I haven't implemented:\n'%=', '<=', '>>=', '&=', '^=' and '|='. They should also be as easy to add\nas the four we just added.\n\n## Example Code\n\nThe `tests/input110.c` program is our testing program:\n\n```c\n#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n```\n\nand produces these results:\n\n```\n18\n12\n45\n5\n```\n\n## Conclusion and What's Next\n\nWe've added some more operators, and the hardest part really was aligning all\nthe tokens, the AST operators and setting the precedence levels and\nright-associativity. After that, we could reuse some of the code generation\ncode in `genAST()` to make our lives a bit easier.\n\nIn the next part of our compiler writing journey, it looks like I'll be adding\nconstant folding to the compiler. [Next step](../44_Fold_Optimisation/Readme.md)\n"
  },
  {
    "path": "43_More_Operators/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->st_posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n  \n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i=0; i < node->nelems; i++) {\n  \n    // Get any initial value\n    initvalue= 0;\n    if (node->initlist != NULL)\n      initvalue= node->initlist[i];\n  \n    // Generate the space for this type\n    switch (size) {\n      case 1:\n        fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n        if (node->initlist != NULL && type== pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++)\n  \tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "43_More_Operators/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "43_More_Operators/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "43_More_Operators/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "43_More_Operators/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(void) {\n  int type, class;\n  struct symtable *ctype;\n\n  // Get the type inside the parentheses\n  type= parse_stars(parse_type(&ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return(type);\n}\n\n// Given a type, check that the latest token is a literal\n// of that type. If an integer literal, return this value.\n// If a string literal, return the label number of the string.\n// Do not scan the next token. If type is P_NONE, relax all\n// parse restrictions\nint parse_literal(int type) {\n\n  // We have a string literal. Store in memory and return the label\n  if (Token.token == T_STRLIT) {\n    if (type == pointer_to(P_CHAR) || type == P_NONE)\n    return(genglobstr(Text));\n  }\n\n  // We have an integer literal. Do some range checking.\n  if (Token.token == T_INTLIT) {\n    switch(type) {\n      case P_CHAR: if (Token.intvalue < 0 || Token.intvalue > 255)\n\t\t     fatal(\"Integer literal value too big for char type\");\n      case P_NONE:\n      case P_INT:\n      case P_LONG: break;\n      default: fatal(\"Type mismatch: integer literal vs. variable\");\n    }\n  } else\n    fatal(\"Expecting an integer literal value\");\n  return(Token.intvalue);\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym=NULL;\n  struct ASTnode *varnode, *exprnode;\n  int casttype;\n  *tree= NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym= addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym= addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym= addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym= addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL) {\n      // If there is a cast\n      if (Token.token == T_LPAREN) {\n\t// Get the type in the cast\n        scan(&Token);\n        casttype= parse_cast();\n\trparen();\n\n\t// Check that the two types are compatible. Change\n\t// the new type so that the literal parse below works.\n\t// A 'void *' casstype can be assigned to any pointer type.\n\tif (casttype == type || (casttype== pointer_to(P_VOID) && ptrtype(type)))\n\t  type= P_NONE;\n\telse\n\t  fatal(\"Type mismatch\");\n      }\n\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n      scan(&Token);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, 0);\n      if (exprnode == NULL)\n        fatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode,\n\t\t\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t// New symbol table entry\n  int nelems= -1;\t// Assume the number of elements won't be given\n  int maxelems;\t\t// The maximum number of elements in the init list\n  int *initlist;\t// The list of initial elements \n  int i=0, j;\n  int casttype, newtype;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token == T_INTLIT) {\n    if (Token.intvalue <= 0)\n      fatald(\"Array size is illegal\", Token.intvalue);\n    nelems= Token.intvalue;\n    scan(&Token);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class,\n\t\t  0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems= nelems;\n    else\n      maxelems= TABLE_INCREMENT;\n    initlist= (int *)malloc(maxelems *sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n      // Get the original type\n      newtype= type;\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n        fatal(\"Too many values in initialisation list\");\n\n      if (Token.token == T_LPAREN) {\n\t// Get the type in the cast\n        scan(&Token);\n        casttype= parse_cast();\n\trparen();\n\n\t// Check that the two types are compatible. Change\n\t// the new type so that the literal parse below works.\n\t// A 'void *' casstype can be assigned to any pointer type.\n\tif (casttype == type || (casttype== pointer_to(P_VOID) && ptrtype(type)))\n\t  newtype= P_NONE;\n\telse\n\t  fatal(\"Type mismatch\");\n\tnewtype= P_NONE;\n      }\n\n      initlist[i++]= parse_literal(newtype);\n      scan(&Token);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n        maxelems += TABLE_INCREMENT;\n        initlist= (int *)realloc(initlist, maxelems *sizeof(int));\n      }\n\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n        scan(&Token);\n\tbreak;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j=i; j < sym->nelems; j++) initlist[j]=0;\n    if (i > nelems) nelems = i;\n    sym->initlist= initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  sym->nelems= nelems;\n  sym->size= sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, C_GLOBAL, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Generate the assembly code for it\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t= declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t== -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead==NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name= NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree= NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL)\n        fatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree== NULL)\n      *gluetree= tree;\n    else\n      *gluetree = mkastnode(A_GLUE, P_NONE, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "43_More_Operators/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(void);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n"
  },
  {
    "path": "43_More_Operators/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\n  A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "43_More_Operators/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken) break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->st_posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n  int type=0;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    scan(&Token);\n\n\n    // If the token after is a type identifier, this is a cast expression\n    switch (Token.token) {\n      case T_IDENT:\n        // We have to see if the identifier matches a typedef.\n        // If not, treat it as an expression.\n        if (findtypedef(Text) == NULL) {\n          n = binexpr(0); break;\n        }\n      case T_VOID:\n      case T_CHAR:\n      case T_INT:\n      case T_LONG:\n      case T_STRUCT:\n      case T_UNION:\n      case T_ENUM:\n\t// Get the type inside the parentheses\n        type= parse_cast();\n        // Skip the closing ')' and then parse the following expression\n        rparen();\n\n      default: n = binexpr(0); // Scan in the expression\n    }\n\n    // We now have at least an expression in n, and possibly a non-zero type in type\n    // if there was a cast. Skip the closing ')' if there was no cast.\n    if (type == 0)\n      rparen();\n    else\n      // Otherwise, make a unary AST node for the cast\n      n= mkastunary(A_CAST, type, n, NULL, 0);\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n        tokentype == T_COLON) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "43_More_Operators/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs();\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs();\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL) genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      if (n->right != NULL) genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->a_intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->a_intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n\tcase A_ASPLUS:\n\t  leftreg= cgadd(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n\tcase A_ASMINUS:\n\t  leftreg= cgsub(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n        case A_ASSTAR:\n\t  leftreg= cgmul(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n        case A_ASSLASH:\n\t  leftreg= cgdiv(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->a_size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (leftreg);\t\t// Not much to do\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "43_More_Operators/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "43_More_Operators/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "43_More_Operators/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "43_More_Operators/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "43_More_Operators/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "43_More_Operators/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "43_More_Operators/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "43_More_Operators/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "43_More_Operators/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "43_More_Operators/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t\t// Negative int literal\n        t->intvalue = -scanint(c);\n        t->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n        t->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n        t->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "43_More_Operators/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and get the compound expression\n\tmatch(T_COLON, \":\");\n\tleft= compound_statement(1); casecount++;\n\n\t// Build a sub-tree with the compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "43_More_Operators/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "43_More_Operators/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input032.c",
    "content": "Unknown variable:cow on line 4 of input032.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input042.c",
    "content": "Undeclared function:fred on line 3 of input042.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input043.c",
    "content": "Undeclared array:b on line 3 of input043.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input044.c",
    "content": "Unknown variable:z on line 3 of input044.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input059.c",
    "content": "Undeclared variable:y on line 3 of input059.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input060.c",
    "content": "Undeclared variable:x on line 3 of input060.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input061.c",
    "content": "Undeclared variable:x on line 3 of input061.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input092.c",
    "content": "Integer literal value too big for char type on line 1 of input092.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input093.c",
    "content": "Expecting an integer literal value on line 1 of input093.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input094.c",
    "content": "Type mismatch: integer literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "43_More_Operators/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "43_More_Operators/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "43_More_Operators/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "43_More_Operators/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "43_More_Operators/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "43_More_Operators/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "43_More_Operators/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "43_More_Operators/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "43_More_Operators/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "43_More_Operators/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "43_More_Operators/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "43_More_Operators/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "43_More_Operators/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "43_More_Operators/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "43_More_Operators/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "43_More_Operators/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "43_More_Operators/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "43_More_Operators/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "43_More_Operators/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "43_More_Operators/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "43_More_Operators/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "43_More_Operators/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "43_More_Operators/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "43_More_Operators/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "43_More_Operators/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "43_More_Operators/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "43_More_Operators/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "43_More_Operators/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "43_More_Operators/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "43_More_Operators/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "43_More_Operators/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "43_More_Operators/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "43_More_Operators/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "43_More_Operators/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "43_More_Operators/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "43_More_Operators/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "43_More_Operators/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "43_More_Operators/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "43_More_Operators/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "43_More_Operators/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "43_More_Operators/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "43_More_Operators/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "43_More_Operators/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "43_More_Operators/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "43_More_Operators/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "43_More_Operators/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "43_More_Operators/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "43_More_Operators/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "43_More_Operators/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "43_More_Operators/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "43_More_Operators/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "43_More_Operators/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "43_More_Operators/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "43_More_Operators/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "43_More_Operators/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "43_More_Operators/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "43_More_Operators/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "43_More_Operators/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "43_More_Operators/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "43_More_Operators/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "43_More_Operators/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "43_More_Operators/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "43_More_Operators/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "43_More_Operators/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "43_More_Operators/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "43_More_Operators/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "43_More_Operators/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "43_More_Operators/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "43_More_Operators/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "43_More_Operators/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "43_More_Operators/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "43_More_Operators/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "43_More_Operators/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "43_More_Operators/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "43_More_Operators/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "43_More_Operators/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "43_More_Operators/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "43_More_Operators/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "43_More_Operators/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "43_More_Operators/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "43_More_Operators/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "43_More_Operators/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "43_More_Operators/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "43_More_Operators/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "43_More_Operators/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "43_More_Operators/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "43_More_Operators/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "43_More_Operators/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "43_More_Operators/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "43_More_Operators/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "43_More_Operators/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "43_More_Operators/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "43_More_Operators/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "43_More_Operators/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return(tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "44_Fold_Optimisation/Readme.md",
    "content": "# Part 44: Constant Folding\n\nIn the last part of our compiler writing journey, I realised that I'd\nhave to add [constant folding](https://en.wikipedia.org/wiki/Constant_folding)\nas an optimisation, so that I could parse expressions as part of doing\nglobal variable declarations.\n\nSo, in this part, I've added the constant folding optimisation for\ngeneral expressions and in the next part I'll rewrite the code for\nglobal variable declarations.\n\n## What is Constant Folding?\n\nConstant folding is a form of optimisation where an expression can be\nevaluated by the compiler at compile time, instead of generating code\nto evaluate the expression at run time.\n\nFor example, we can see that `x= 5 + 4 * 5;` is really the same as\n`x= 25;`, so we can let the compiler evaluate the expression and just output\nthe assembly code for `x= 25;`.\n\n## So How Do We Do It?\n\nThe answer is: look for sub-trees in an AST tree where the leaves are integer\nliterals. If there is a binary operation which has two integer\nliterals leaves, the compiler can evaluate the expression and replace the\nsub-tree with a single integer literal node.\n\nSimilarly, if there is a unary operation with an integer literal leaf\nchild, then the compiler can also evaluate the expression and replace the\nsub-tree with a single integer literal node.\n\nOnce we can do this for sub-trees, we can write a function to traverse the\nentire tree looking for sub-trees to fold. At any node, we can do this\nalgorithm:\n\n  1. Try to fold and replace the left child, i.e. recursively.\n  1. Try to fold and replace the right child, i.e. recursively.\n  1. If it's a binary operation with two literals child leaves, fold that.\n  1. If it's a unary operation with one literal child leaf, fold that.\n\nThe fact that we replace the sub-trees means we recursively optimise the\nedges of the tree first, then work back up the tree to the root of the\ntree. An example:\n\n```\n     *         *        *     50\n    / \\       / \\      / \\\n   +   -     10  -    10  5\n  / \\ / \\       / \\\n  6 4 8 3      8   3\n```\n\n## A New File, `opt.c`\n\nI've created a new source file for our compiler, `opt.c` and in it I've\nrewritten the same three functions, `fold2()`, `fold1()` and `fold()`\nthat are in the [SubC](http://www.t3x.org/subc/) compiler written by\nNils M Holm.\n\nOne thing that Nils spends a lot of time in his code is to get the\ncalculations correct. This is important when the compiler is a cross-compiler.\nFor example, if we do the constant folding on a 64-bit machine, then the\nrange we have for integer literals is much bigger than for 32-bit machines.\nAny constant folding we do on the 64-bit machine may not be the same\nresult (due to lack of truncation) than the calculation of the same\nexpression on a 32-bit machine.\n\nI know that this is an important concern, but I will stick with our\n\"KISS principle\" and write simple code for now. As required, I'll go\nback and fix it.\n\n## Folding Binary Operations\n\nHere is the code to fold AST sub-trees which are binary operations on\ntwo children. I'm only folding a few operations; there are many more\nin `expr.c` that we could also fold.\n\n```c\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n```\n\nAnother function will call `fold2()` and this ensures that both `n->left`\nand `n->right` are non-NULL pointers to A_INTLIT leaf nodes. Now that we\nhave the values from both children, we can get to work.\n\n```c\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n        return (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n```\n\nWe fold the normal four maths operations. Note the special code for\ndivision: if we try to divide by zero, the compiler will crash. Instead,\nwe leave the sub-tree intact and let the code crash once it becomes\nan executable! Obviously, there is opportunity for a `fatal()` call here.\nWe leave the switch statement with a single value `val` that represents\nthe calculated value of the sub-tree. Time to replace the sub-tree.\n\n```c\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n```\n\nSo a binary AST tree goes in, and a leaf AST node (hopefully) comes out.\n\n## Folding Unary Operations\n\nNow that you've seen folding on binary operations, the code for unary\noperations should be straight forward. I am only folding two unary\noperations, but there is room to add more.\n\n```c\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n```\n\nThere is one small wrinkle with implementing `fold1()` in our compiler,\nand that is we have AST nodes to widen values from one type to another.\nFor example, in this expression `x= 3000 + 1;`, the '1' is parsed as\na `char` literal. It needs to be widened to be of type `int` so that it\ncan be added to the '3000'. The compiler without optimisation generates this\nAST tree:\n\n```\n       A_ADD\n      /     \\\n  A_INTLIT A_WIDEN\n    3000      \\\n           A_INTLIT\n               1\n```\n\nWhat we do here is treat the A_WIDEN as a unary AST operation and copy the\nliteral value from the child and return a leaf node with the widened type\nand with the literal value.\n\n## Recursively Folding a Whole AST Tree\n\nWe have two functions to deal with the edges of the tree. Now we can\ncode up the recursive function to optimise the edges and work from the\nedges back up to the root of the tree.\n\n```c\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n\n  // Return the possibly modified tree\n  return (n);\n}\n```\n\nThe first thing to do is return NULL on a NULL tree. This allows us to\nrecursively call `fold()` on this node's children on the following two lines\nof code. We have just optimised the sub-trees below us.\n\nNow, for an AST node with two integer literal leaf children, call `fold2()`\nto optimise them away (if possible). And if we have only one\ninteger literal leaf child, call `fold1()` to do the same to it.\n\nWe either have trimmed the tree, or the tree is unchanged. Either way,\nwe can now return it to the recursion level above us.\n\n## A Generic Optimisation Function\n\nConstant folding is only one optimisation we can do on our AST tree; there\nwill be others later. Thus, it makes sense to write a front-end function\nthat applies all the optimisations to the tree. Here it is with just\nconstant folding:\n\n```c\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n```\n\nWe can  extend it later. This gets called in `function_declaration()` in `decl.c`.\nOnce we have parsed a function and its body, we put the A_FUNCTION node on the top of the tree, and:\n\n```c\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree= optimise(tree);\n```\n\n## An Example Function\n\nThe following program, `tests/input111.c`, should put the folding code\nthrough its paces.\n\n```c\n#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n```\n\nThe compiler should replace the initialisation with `x=2029;`. Let's do\na `cwj -T -S tests/input111.c` and see:\n\n```\n$ ./cwj -T -S z.c\n    A_INTLIT 2029\n  A_WIDEN\n  A_IDENT x\nA_ASSIGN\n...\n$ ./cwj -o tests/input111 tests/input111.c\n$ ./tests/input111\n2029\n```\n\nIt seems to work, and the compiler still passes all 110 previous tests, so\nfor now it does its job.\n\n## Conclusion and What's Next\n\nI was going to leave optimisation to the end of our journey, but I think\nit's good to see one type of optimisation now.\n\nIn the next part of our compiler writing journey, we will replace our\ncurrent global declaration parser with code that evaluates expressions\nusing `binexpr()` and this new constant folding code. [Next step](../45_Globals_Again/Readme.md)\n"
  },
  {
    "path": "44_Fold_Optimisation/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->st_posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n  \n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i=0; i < node->nelems; i++) {\n  \n    // Get any initial value\n    initvalue= 0;\n    if (node->initlist != NULL)\n      initvalue= node->initlist[i];\n  \n    // Generate the space for this type\n    switch (size) {\n      case 1:\n        fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n        if (node->initlist != NULL && type== pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++)\n  \tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "44_Fold_Optimisation/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(void) {\n  int type, class;\n  struct symtable *ctype;\n\n  // Get the type inside the parentheses\n  type= parse_stars(parse_type(&ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return(type);\n}\n\n// Given a type, check that the latest token is a literal\n// of that type. If an integer literal, return this value.\n// If a string literal, return the label number of the string.\n// Do not scan the next token. If type is P_NONE, relax all\n// parse restrictions\nint parse_literal(int type) {\n\n  // We have a string literal. Store in memory and return the label\n  if (Token.token == T_STRLIT) {\n    if (type == pointer_to(P_CHAR) || type == P_NONE)\n    return(genglobstr(Text));\n  }\n\n  // We have an integer literal. Do some range checking.\n  if (Token.token == T_INTLIT) {\n    switch(type) {\n      case P_CHAR: if (Token.intvalue < 0 || Token.intvalue > 255)\n\t\t     fatal(\"Integer literal value too big for char type\");\n      case P_NONE:\n      case P_INT:\n      case P_LONG: break;\n      default: fatal(\"Type mismatch: integer literal vs. variable\");\n    }\n  } else\n    fatal(\"Expecting an integer literal value\");\n  return(Token.intvalue);\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym=NULL;\n  struct ASTnode *varnode, *exprnode;\n  int casttype;\n  *tree= NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym= addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym= addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym= addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym= addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL) {\n      // If there is a cast\n      if (Token.token == T_LPAREN) {\n\t// Get the type in the cast\n        scan(&Token);\n        casttype= parse_cast();\n\trparen();\n\n\t// Check that the two types are compatible. Change\n\t// the new type so that the literal parse below works.\n\t// A 'void *' casstype can be assigned to any pointer type.\n\tif (casttype == type || (casttype== pointer_to(P_VOID) && ptrtype(type)))\n\t  type= P_NONE;\n\telse\n\t  fatal(\"Type mismatch\");\n      }\n\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n      scan(&Token);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, 0);\n      if (exprnode == NULL)\n        fatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode,\n\t\t\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t// New symbol table entry\n  int nelems= -1;\t// Assume the number of elements won't be given\n  int maxelems;\t\t// The maximum number of elements in the init list\n  int *initlist;\t// The list of initial elements \n  int i=0, j;\n  int casttype, newtype;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token == T_INTLIT) {\n    if (Token.intvalue <= 0)\n      fatald(\"Array size is illegal\", Token.intvalue);\n    nelems= Token.intvalue;\n    scan(&Token);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class,\n\t\t  0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems= nelems;\n    else\n      maxelems= TABLE_INCREMENT;\n    initlist= (int *)malloc(maxelems *sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n      // Get the original type\n      newtype= type;\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n        fatal(\"Too many values in initialisation list\");\n\n      if (Token.token == T_LPAREN) {\n\t// Get the type in the cast\n        scan(&Token);\n        casttype= parse_cast();\n\trparen();\n\n\t// Check that the two types are compatible. Change\n\t// the new type so that the literal parse below works.\n\t// A 'void *' casstype can be assigned to any pointer type.\n\tif (casttype == type || (casttype== pointer_to(P_VOID) && ptrtype(type)))\n\t  newtype= P_NONE;\n\telse\n\t  fatal(\"Type mismatch\");\n\tnewtype= P_NONE;\n      }\n\n      initlist[i++]= parse_literal(newtype);\n      scan(&Token);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n        maxelems += TABLE_INCREMENT;\n        initlist= (int *)realloc(initlist, maxelems *sizeof(int));\n      }\n\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n        scan(&Token);\n\tbreak;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j=i; j < sym->nelems; j++) initlist[j]=0;\n    if (i > nelems) nelems = i;\n    sym->initlist= initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  sym->nelems= nelems;\n  sym->size= sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, C_GLOBAL, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree= optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t= declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t== -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead==NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name= NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree= NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL)\n        fatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree== NULL)\n      *gluetree= tree;\n    else\n      *gluetree = mkastnode(A_GLUE, P_NONE, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(void);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "44_Fold_Optimisation/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\n  A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "44_Fold_Optimisation/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken) break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->st_posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n  int type=0;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    scan(&Token);\n\n\n    // If the token after is a type identifier, this is a cast expression\n    switch (Token.token) {\n      case T_IDENT:\n        // We have to see if the identifier matches a typedef.\n        // If not, treat it as an expression.\n        if (findtypedef(Text) == NULL) {\n          n = binexpr(0); break;\n        }\n      case T_VOID:\n      case T_CHAR:\n      case T_INT:\n      case T_LONG:\n      case T_STRUCT:\n      case T_UNION:\n      case T_ENUM:\n\t// Get the type inside the parentheses\n        type= parse_cast();\n        // Skip the closing ')' and then parse the following expression\n        rparen();\n\n      default: n = binexpr(0); // Scan in the expression\n    }\n\n    // We now have at least an expression in n, and possibly a non-zero type in type\n    // if there was a cast. Skip the closing ')' if there was no cast.\n    if (type == 0)\n      rparen();\n    else\n      // Otherwise, make a unary AST node for the cast\n      n= mkastunary(A_CAST, type, n, NULL, 0);\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n        tokentype == T_COLON) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs();\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs();\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL) genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      if (n->right != NULL) genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->a_intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->a_intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n\tcase A_ASPLUS:\n\t  leftreg= cgadd(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n\tcase A_ASMINUS:\n\t  leftreg= cgsub(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n        case A_ASSTAR:\n\t  leftreg= cgmul(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n        case A_ASSLASH:\n\t  leftreg= cgdiv(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->a_size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (leftreg);\t\t// Not much to do\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "44_Fold_Optimisation/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "44_Fold_Optimisation/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "44_Fold_Optimisation/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "44_Fold_Optimisation/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "44_Fold_Optimisation/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "44_Fold_Optimisation/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "44_Fold_Optimisation/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t\t// Negative int literal\n        t->intvalue = -scanint(c);\n        t->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n        t->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n        t->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and get the compound expression\n\tmatch(T_COLON, \":\");\n\tleft= compound_statement(1); casecount++;\n\n\t// Build a sub-tree with the compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input032.c",
    "content": "Unknown variable:cow on line 4 of input032.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input042.c",
    "content": "Undeclared function:fred on line 3 of input042.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input043.c",
    "content": "Undeclared array:b on line 3 of input043.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input044.c",
    "content": "Unknown variable:z on line 3 of input044.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input059.c",
    "content": "Undeclared variable:y on line 3 of input059.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input060.c",
    "content": "Undeclared variable:x on line 3 of input060.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input061.c",
    "content": "Undeclared variable:x on line 3 of input061.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input092.c",
    "content": "Integer literal value too big for char type on line 1 of input092.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input093.c",
    "content": "Expecting an integer literal value on line 1 of input093.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input094.c",
    "content": "Type mismatch: integer literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "44_Fold_Optimisation/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "44_Fold_Optimisation/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "44_Fold_Optimisation/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return(tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "45_Globals_Again/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "45_Globals_Again/Readme.md",
    "content": "# Part 45: Global Variable Declarations, revisited\n\nTwo parts ago, I was trying to compile this line:\n\n```c\nenum { TEXTLEN = 512 };         // Length of identifiers in input\nextern char Text[TEXTLEN + 1];\n```\n\nand realised that our declaration parsing code could only deal with\na single integer literal as the size of an array. But my compiler\ncode, as shown above, uses an expression with two integer literals.\n\nIn the last part, I added constant folding to the compiler so that\nan expression of integer literals will be folded down to a single\ninteger literal.\n\nNow we need to discard all of that  wonderful hand-written parsing of\nthe literal value and associated casting, and call our expression\nparser to get an AST tree with the literal value in it.\n\n## Keep or Discard `parse_literal()`?\n\nIn our current compiler in `decl.c`, we have a function called\n`parse_literal()` which does the manual parsing of strings and integer\nliterals. Should we keep it as a function, or just throw it away and\ncall `binexpr()` manually elsewhere?\n\nI've decided to keep the function, toss all the existing code and\nchange the purpose of this function a little bit. It will now\nalso parse any cast which precedes an expression with several literal\nvalues.\n\nThe function header in `decl.c` is now:\n\n```c\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type);\n```\n\nSo, it's a drop-in replacement for the old `parse_literal()` except\nthat any cast parsing code we had before can be discarded. Let's now\nlook at the new code in `parse_literal()`.\n\n```c\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree= optimise(binexpr(0));\n```\n\nAhah. We call `binexpr()` to parse whatever expression is at this point\nin the input file, and then `optimise()` to fold all the literal expressions.\n\nNow, for this to be a tree we can use, the root node should be either\nan A_INTLIT, an A_STRLIT or a A_CAST (if there was a preceding cast).\n\n```c\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type= tree->type;\n    tree= tree->left;\n  }\n```\n\nIt was a cast, so we get rid of the A_CAST node but keep the type\nthat the child was cast to.\n\n\n```c\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n```\n\nOops, they gave us something we cannot use, so tell them and stop.\n\n```c\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return(tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue==0)\n      return(0);\n  }\n```\n\nWe need to be able to accept both of these as input:\n\n```c\n              char *c= \"Hello\";\n              char *c= (char *)0;\n```\n\nand the two inner IF statements above match the two input lines shown.\nIf not a string literal, ...\n\n```c\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return(tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return(0);    // Keep -Wall happy\n}\n```\n\nThis took me a while to figure out. We have to parse these:\n\n```c\n  long  x= 3;    // allow this, where 3 is type char\n  char  y= 4000; // prevent this, where 4000 is too wide\n  char *z= 4000; // prevent this, as z is not integer type\n```\n\nso the IF statement checks the input type and ensures that it is\nwide enough to accept the integer literal.\n\n## The Other Parse Changes in `decl.c`\n\nNow that we have a function that can parse a literal expression\npossibly preceded by a cast, we can use it. This is where we toss\nout our old cast parsing code and replace it. The changes are:\n\n```c\n// Parse a scalar declaration\nstatic struct symtable *scalar_declaration(...) {\n    ...\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n    }\n    ...\n}\n\n// Parse an array declaration\nstatic struct symtable *array_declaration(...) {\n\n  ...\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems= parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n\n  ...\n  // Get the list of initial values\n  while (1) {\n    ...\n    initlist[i++]= parse_literal(type);\n    ...\n  }\n  ...\n}\n```\n\nBy doing this, we lose about 20 to 30 lines of code to parse any\npossible cast that used to come before the old `parse_literal()`.\nMind you, we had to add 100 lines of constant folding to get that\n30 line reduction! Luckily, the constant folding is used in general\nexpressions as well as here, so it is still a win.\n\n## One `expr.c` Change\n\nThere is one further change to our compiler code to support the\nnew `parse_literal()`. In our general function to parse expressions,\n`binexpr()`, we now must inform it that an expression can be ended\nby a '}' token, such as appears here:\n\n```c\n  int fred[]= { 1, 2, 6 };\n```\n\nThe small change to `binexpr()` is:\n\n```c\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n        tokentype == T_RBRACKET || tokentype == T_COMMA ||\n        tokentype == T_COLON || tokentype == T_RBRACE) {    // T_RBRACE is new\n      left->rvalue = 1;\n      return (left);\n    }\n```\n\n## Code to Test The Changes\n\nOur existing tests will test the situation where there is a single literal\nvalue to initialise a global variable. This code in `tests/input112.c`\ntests both a literal expression to initialise a scalar variable, and\na literal expression as the size of an array:\n\n```c\n#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n```\n\n## Conclusion and What's Next\n\nIn the next part of our compiler writing journey, I will probably feed\nmore of the compiler source to itself and see what we still have to\nimplement. [Next step](../46_Void_Functions/Readme.md)\n"
  },
  {
    "path": "45_Globals_Again/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->st_posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n  \n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i=0; i < node->nelems; i++) {\n  \n    // Get any initial value\n    initvalue= 0;\n    if (node->initlist != NULL)\n      initvalue= node->initlist[i];\n  \n    // Generate the space for this type\n    switch (size) {\n      case 1:\n        fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n        if (node->initlist != NULL && type== pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++)\n  \tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "45_Globals_Again/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "45_Globals_Again/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "45_Globals_Again/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "45_Globals_Again/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(void) {\n  int type, class;\n  struct symtable *ctype;\n\n  // Get the type inside the parentheses\n  type= parse_stars(parse_type(&ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return(type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree= optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type= tree->type;\n    tree= tree->left;\n  }\n\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return(tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue==0)\n      return(0);\n  }\n\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return(tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return(0);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym=NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree= NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym= addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym= addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym= addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym= addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, 0);\n      if (exprnode == NULL)\n        fatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode,\n\t\t\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t// New symbol table entry\n  int nelems= -1;\t// Assume the number of elements won't be given\n  int maxelems;\t\t// The maximum number of elements in the init list\n  int *initlist;\t// The list of initial elements \n  int i=0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems= parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class,\n\t\t  0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems= nelems;\n    else\n      maxelems= TABLE_INCREMENT;\n    initlist= (int *)malloc(maxelems *sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n        fatal(\"Too many values in initialisation list\");\n\n      initlist[i++]= parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n        maxelems += TABLE_INCREMENT;\n        initlist= (int *)realloc(initlist, maxelems *sizeof(int));\n      }\n\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n        scan(&Token);\n\tbreak;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j=i; j < sym->nelems; j++) initlist[j]=0;\n    if (i > nelems) nelems = i;\n    sym->initlist= initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  sym->nelems= nelems;\n  sym->size= sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, C_GLOBAL, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree= optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t= declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t== -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead==NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name= NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree= NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL)\n        fatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree== NULL)\n      *gluetree= tree;\n    else\n      *gluetree = mkastnode(A_GLUE, P_NONE, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "45_Globals_Again/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(void);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "45_Globals_Again/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\n  A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "45_Globals_Again/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken) break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->st_posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n  int type=0;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    scan(&Token);\n\n\n    // If the token after is a type identifier, this is a cast expression\n    switch (Token.token) {\n      case T_IDENT:\n        // We have to see if the identifier matches a typedef.\n        // If not, treat it as an expression.\n        if (findtypedef(Text) == NULL) {\n          n = binexpr(0); break;\n        }\n      case T_VOID:\n      case T_CHAR:\n      case T_INT:\n      case T_LONG:\n      case T_STRUCT:\n      case T_UNION:\n      case T_ENUM:\n\t// Get the type inside the parentheses\n        type= parse_cast();\n        // Skip the closing ')' and then parse the following expression\n        rparen();\n\n      default: n = binexpr(0); // Scan in the expression\n    }\n\n    // We now have at least an expression in n, and possibly a non-zero type in type\n    // if there was a cast. Skip the closing ')' if there was no cast.\n    if (type == 0)\n      rparen();\n    else\n      // Otherwise, make a unary AST node for the cast\n      n= mkastunary(A_CAST, type, n, NULL, 0);\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n        tokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "45_Globals_Again/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs();\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs();\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL) genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      if (n->right != NULL) genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->a_intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->a_intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n\tcase A_ASPLUS:\n\t  leftreg= cgadd(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n\tcase A_ASMINUS:\n\t  leftreg= cgsub(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n        case A_ASSTAR:\n\t  leftreg= cgmul(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n        case A_ASSLASH:\n\t  leftreg= cgdiv(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->a_size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (leftreg);\t\t// Not much to do\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "45_Globals_Again/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "45_Globals_Again/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "45_Globals_Again/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "45_Globals_Again/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "45_Globals_Again/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "45_Globals_Again/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "45_Globals_Again/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "45_Globals_Again/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn++ = suffix;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "45_Globals_Again/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "45_Globals_Again/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "45_Globals_Again/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int c;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn '\\a';\n      case 'b':\n\treturn '\\b';\n      case 'f':\n\treturn '\\f';\n      case 'n':\n\treturn '\\n';\n      case 'r':\n\treturn '\\r';\n      case 't':\n\treturn '\\t';\n      case 'v':\n\treturn '\\v';\n      case '\\\\':\n\treturn '\\\\';\n      case '\"':\n\treturn '\"';\n      case '\\'':\n\treturn '\\'';\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0;\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789\", c)) >= 0) {\n    val = val * 10 + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// A pointer to a rejected token\nstatic struct token *Rejtoken = NULL;\n\n// Reject the token that we just scanned\nvoid reject_token(struct token *t) {\n  if (Rejtoken != NULL)\n    fatal(\"Can't reject token twice\");\n  Rejtoken = t;\n}\n\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have any rejected token, return it\n  if (Rejtoken != NULL) {\n    t = Rejtoken;\n    Rejtoken = NULL;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t\t// Negative int literal\n        t->intvalue = -scanint(c);\n        t->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n        t->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n        t->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "45_Globals_Again/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and get the compound expression\n\tmatch(T_COLON, \":\");\n\tleft= compound_statement(1); casecount++;\n\n\t// Build a sub-tree with the compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "45_Globals_Again/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input032.c",
    "content": "Unknown variable:cow on line 4 of input032.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input042.c",
    "content": "Undeclared function:fred on line 3 of input042.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input043.c",
    "content": "Undeclared array:b on line 3 of input043.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input044.c",
    "content": "Unknown variable:z on line 3 of input044.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input059.c",
    "content": "Undeclared variable:y on line 3 of input059.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input060.c",
    "content": "Undeclared variable:x on line 3 of input060.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input061.c",
    "content": "Undeclared variable:x on line 3 of input061.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input093.c",
    "content": "Unknown variable:fred on line 1 of input093.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "45_Globals_Again/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "45_Globals_Again/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "45_Globals_Again/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "45_Globals_Again/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "45_Globals_Again/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "45_Globals_Again/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "45_Globals_Again/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "45_Globals_Again/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "45_Globals_Again/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "45_Globals_Again/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "45_Globals_Again/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "45_Globals_Again/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "45_Globals_Again/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "45_Globals_Again/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "45_Globals_Again/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "45_Globals_Again/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "45_Globals_Again/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "45_Globals_Again/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "45_Globals_Again/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "45_Globals_Again/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "45_Globals_Again/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "45_Globals_Again/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "45_Globals_Again/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "45_Globals_Again/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "45_Globals_Again/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "45_Globals_Again/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "45_Globals_Again/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "45_Globals_Again/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "45_Globals_Again/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "45_Globals_Again/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "45_Globals_Again/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "45_Globals_Again/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "45_Globals_Again/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "45_Globals_Again/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "45_Globals_Again/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "45_Globals_Again/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "45_Globals_Again/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "45_Globals_Again/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return(tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "46_Void_Functions/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "46_Void_Functions/Readme.md",
    "content": "# Part 46: Void Function Parameters and Scanning Changes\n\nIn this part of our compiler writing journey, I've made several changes\nwhich involve the scanner and the parser.\n\n## Void Function Parameters\n\nWe start with this common C construct to indicate that a function has no\nparameters:\n\n```c\nint fred(void);         // Void means no parameters, but\nint fred();             // No parameters also means no parameters\n```\n\nIt does seem strange that we already have a way of indicating no parameters\nbut, anyway, it's a common thing so we need to support it.\n\nThe problem is that, once we hit the left parenthesis, we fall into\nthe `declaration_list()` function in `decl.c`. This has been set up to\nparse a type with a definite following identifier. It's not going to be easy\nto alter it to deal with a type and *no* identifier. So we need to go back\nto the `param_declaration_list()` function and parse the 'void' ')' tokens\nthere.\n\nI already have a function in the scanner called `reject_token()` in\n`scan.c`. We should be able to scan a token, look at it, decide we don't\nwant it, and reject it. Then, the next scanned token will be the one\nwe reject.\n\nI've never used this function and, as it turns out, it was broken. Anyway,\nI took a step back and decided that it would be easier to *peek* at the\nnext token. If we decide we like it, we can scan it in as per normal. If\nwe don't like it, we don't have to do anything: it will get scanned in\non the next real token scan.\n\nNow, why do we need this? It's because our pseudo-code for dealing with\n'void' in the parameter list will be:\n\n```\n  parse the '('\n  if the next token is 'void' {\n    peek at the one after it\n    if the one after 'void' is ')',\n    then return zero parameters\n  }\n  call declaration_list() to get the real parameters\n  so that 'void' is still the current token\n```\n\nWe need to do the peek because both of the following are legal:\n\n```c\nint fred(void);\nint jane(void *ptr, int x, int y);\n```\n\nIf we scan and parse the next token after 'void' and see it is the asterisk,\nthen we have lost the 'void' token. When we then call `declaration_list()`,\nthe first token it will see is the asterisk and it will get upset. Thus,\nwe need the ability to peek beyond the current token while keeping the current\ntoken intact.\n\n## New Scanner Code\n\nIn `data.h` we have a new token variable:\n\n```c\nextern_ struct token Token;             // Last token scanned\nextern_ struct token Peektoken;         // A look-ahead token\n```\n\nand `Peektoken.token` is intialised to zero by code in `main.c`. We modify\nthe main `scan()` function in `scan.c` as follows:\n\n```c\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  ...\n}\n```\n\nIf `Peektoken.token` remains zero, we get the next token. But once\nsomething is stored in `Peektoken`, then that will be the next token we\nreturn.\n\n## Declaration Modifications\n\nNow that we can peek ahead at the next token, let's put it into action.\nWe modify the code in `param_declaration_list()` as follows:\n\n```c\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n        // Move the Peektoken into the Token\n        paramcnt= 0; scan(&Token); break;\n      }\n    }\n    ...\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    ...\n  }\n```\n\nAssume that we have scanned in the 'void'. We now `scan(&Peektoken);` to\nsee what's up next without altering the current `Token`. If that's a\nright parenthesis, we can leave with `paramcnt` set to zero after skipping\nthe 'void' token.\n\nBut if the next token wasn't a right parenthesis, we still have `Token`\nset to 'void' and we can now call `declaration_list()` to get the\nactual list of parameters.\n\n## Hex and Octal Integer Constants\n\nI found the above problem because I've started to feed the compiler's\nsource code to itself. Once I had fixed the 'void' parameter issue, the\nnext thing that I found was that the compiler is unable to parse hex\nand octal constants like `0x314A` and `0073`.\n\nLuckily, the [SubC](http://www.t3x.org/subc/) compiler written by Nils M Holm\nhas code to do this, and I can borrow it wholesale to add to our compiler.\nWe need to modify the `scanint()` function in `scan.c` to do this:\n\n```c\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // NEW CODE: Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n```\n\nWe already had the `k= chrpos(\"0123456789\")` code in the function to deal with\ndecimal literal values. The new code above this now scans for a leading '0'\ndigit. If it sees this, it checks the following character. If it's an 'x',\nthe radix is 16; if not, the radix is 8.\n\nThe other change is that we multiply the previous value by the radix\ninstead of the constant 10. It's a very elegant way to solve this problem,\nand many thanks to Nils for writing the code.\n\n## More Character Constants\n\nThe next problem I hit was code in our compiler that says:\n\n```c\n   if (*posn == '\\0')\n```\n\nThat's a character literal which our compiler doesn't recognise. We will\nneed to modify `scanch()` in `scan.c` to deal with character literals\nwhich are specified as octal values. But character literals\nwhich are specified as hexadecimal values are also possible, e.g. '\\0x41'.\nAgain, the code from SubC comes to our rescue:\n\n```c\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return n;\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      ...\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\t\t\t// Code from SubC\n        for (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n          if (++i > 3)\n            break;\n          c2 = c2 * 8 + (c - '0');\n        }\n        putback(c);             // Put back the first non-octal char\n        return (c2);\n      case 'x':\n        return hexchar();\t// Code from SubC\n      default:\n        fatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);                   // Just an ordinary old character!\n}\n```\n\nAgain, it's nice and elegant code. However, we now have two code\nfragments to do hex conversion and three code fragments to do radix\nconversion, so there is still some potential refactoring here.\n\n# Conclusion and What's Next\n\nWe mostly made changes to the scanner in this part of the journey.\nThey were not earth shattering changes, but they are some of the\nlittle things that we need to get done to have the compiler be\nself-compiling.\n\nTwo big things that we will need to tackle are static functions and\nvariables, and the `sizeof()` operator. \n\nIn the next part of our compiler writing journey, I will probably\nwork on the `sizeof()` operator because `static` still scares me a bit! [Next step](../47_Sizeof/Readme.md)\n"
  },
  {
    "path": "46_Void_Functions/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->st_posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n  \n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i=0; i < node->nelems; i++) {\n  \n    // Get any initial value\n    initvalue= 0;\n    if (node->initlist != NULL)\n      initvalue= node->initlist[i];\n  \n    // Generate the space for this type\n    switch (size) {\n      case 1:\n        fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n        if (node->initlist != NULL && type== pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++)\n  \tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "46_Void_Functions/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "46_Void_Functions/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "46_Void_Functions/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "46_Void_Functions/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(void) {\n  int type, class;\n  struct symtable *ctype;\n\n  // Get the type inside the parentheses\n  type= parse_stars(parse_type(&ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return(type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree= optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type= tree->type;\n    tree= tree->left;\n  }\n\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return(tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue==0)\n      return(0);\n  }\n\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return(tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return(0);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym=NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree= NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym= addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym= addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym= addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym= addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, 0);\n      if (exprnode == NULL)\n        fatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode,\n\t\t\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t// New symbol table entry\n  int nelems= -1;\t// Assume the number of elements won't be given\n  int maxelems;\t\t// The maximum number of elements in the init list\n  int *initlist;\t// The list of initial elements \n  int i=0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems= parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class,\n\t\t  0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems= nelems;\n    else\n      maxelems= TABLE_INCREMENT;\n    initlist= (int *)malloc(maxelems *sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n        fatal(\"Too many values in initialisation list\");\n\n      initlist[i++]= parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n        maxelems += TABLE_INCREMENT;\n        initlist= (int *)realloc(initlist, maxelems *sizeof(int));\n      }\n\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n        scan(&Token);\n\tbreak;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j=i; j < sym->nelems; j++) initlist[j]=0;\n    if (i > nelems) nelems = i;\n    sym->initlist= initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  sym->nelems= nelems;\n  sym->size= sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n        paramcnt= 0; scan(&Token); break;\n      }\n    }\n\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, C_GLOBAL, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree= optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t= declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t== -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead==NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name= NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree= NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL)\n        fatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree== NULL)\n      *gluetree= tree;\n    else\n      *gluetree = mkastnode(A_GLUE, P_NONE, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "46_Void_Functions/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(void);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "46_Void_Functions/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\n  A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "46_Void_Functions/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken) break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->st_posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n  int type=0;\n\n  switch (Token.token) {\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    scan(&Token);\n\n\n    // If the token after is a type identifier, this is a cast expression\n    switch (Token.token) {\n      case T_IDENT:\n        // We have to see if the identifier matches a typedef.\n        // If not, treat it as an expression.\n        if (findtypedef(Text) == NULL) {\n          n = binexpr(0); break;\n        }\n      case T_VOID:\n      case T_CHAR:\n      case T_INT:\n      case T_LONG:\n      case T_STRUCT:\n      case T_UNION:\n      case T_ENUM:\n\t// Get the type inside the parentheses\n        type= parse_cast();\n        // Skip the closing ')' and then parse the following expression\n        rparen();\n\n      default: n = binexpr(0); // Scan in the expression\n    }\n\n    // We now have at least an expression in n, and possibly a non-zero type in type\n    // if there was a cast. Skip the closing ')' if there was no cast.\n    if (type == 0)\n      rparen();\n    else\n      // Otherwise, make a unary AST node for the cast\n      n= mkastunary(A_CAST, type, n, NULL, 0);\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n        tokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "46_Void_Functions/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs();\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs();\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL) genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      if (n->right != NULL) genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->a_intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->a_intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n\tcase A_ASPLUS:\n\t  leftreg= cgadd(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n\tcase A_ASMINUS:\n\t  leftreg= cgsub(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n        case A_ASSTAR:\n\t  leftreg= cgmul(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n        case A_ASSLASH:\n\t  leftreg= cgdiv(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->a_size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (leftreg);\t\t// Not much to do\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "46_Void_Functions/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "46_Void_Functions/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "46_Void_Functions/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "46_Void_Functions/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "46_Void_Functions/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "46_Void_Functions/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "46_Void_Functions/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "46_Void_Functions/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "46_Void_Functions/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix; posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token= 0;\t\t// and set there is no lookahead token\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "46_Void_Functions/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "46_Void_Functions/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "46_Void_Functions/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return n;\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn hexchar();\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "46_Void_Functions/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and get the compound expression\n\tmatch(T_COLON, \":\");\n\tleft= compound_statement(1); casecount++;\n\n\t// Build a sub-tree with the compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "46_Void_Functions/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input032.c",
    "content": "Unknown variable:cow on line 4 of input032.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input042.c",
    "content": "Undeclared function:fred on line 3 of input042.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input043.c",
    "content": "Undeclared array:b on line 3 of input043.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input044.c",
    "content": "Unknown variable:z on line 3 of input044.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input059.c",
    "content": "Undeclared variable:y on line 3 of input059.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input060.c",
    "content": "Undeclared variable:x on line 3 of input060.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input061.c",
    "content": "Undeclared variable:x on line 3 of input061.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input093.c",
    "content": "Unknown variable:fred on line 1 of input093.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "46_Void_Functions/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "46_Void_Functions/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "46_Void_Functions/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "46_Void_Functions/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "46_Void_Functions/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "46_Void_Functions/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "46_Void_Functions/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "46_Void_Functions/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "46_Void_Functions/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "46_Void_Functions/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "46_Void_Functions/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "46_Void_Functions/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "46_Void_Functions/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "46_Void_Functions/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "46_Void_Functions/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "46_Void_Functions/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "46_Void_Functions/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "46_Void_Functions/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "46_Void_Functions/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "46_Void_Functions/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "46_Void_Functions/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "46_Void_Functions/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "46_Void_Functions/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "46_Void_Functions/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "46_Void_Functions/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "46_Void_Functions/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "46_Void_Functions/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "46_Void_Functions/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "46_Void_Functions/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "46_Void_Functions/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "46_Void_Functions/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "46_Void_Functions/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "46_Void_Functions/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "46_Void_Functions/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "46_Void_Functions/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "46_Void_Functions/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "46_Void_Functions/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "46_Void_Functions/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return(tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "47_Sizeof/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "47_Sizeof/Readme.md",
    "content": "# Part 47: A Subset of `sizeof`\n\nIn a real C compiler, the `sizeof()` operator gives the size in bytes of:\n\n + a type definition, and\n + the type of an expression\n\nI looked at the code in our compiler and I'm only using `sizeof()` for\nthe first of the two options above, so I'm only going to implement the\nfirst one. This makes things a bit easier as we can assume that\nthe tokens inside the `sizeof()` are a type definition.\n\n## New Token and Keyword\n\nWe need a \"sizeof\" keyword and a new token, T_SIZEOF. As per usual,\nI'll let you look at the changes to `scan.c`.\n\nNow, when adding new tokens, we also have to update the:\n\n```c\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n```\n\nI initially forgot to do this, and when debugging I was seeing the \"wrong\"\ntoken description for the tokens after \"default\". Oops!\n\n## Changes to the Parser\n\nThe `sizeof()` operator is part of expression parsing, as it takes an\nexpression and returns a new value. We can do things like:\n\n```c\n  int x= 43 + sizeof(char);\n```\n\nThus, we are going to modify `expr.c` to add `sizeof()`. It isn't a binary\noperator, and it's not a prefix or postfix operator, so the best place to\nadd `sizeof()` is as part of parsing primary expressions.\n\nIn fact, once I found my silly bugs, the amount of new code to do `sizeof()`\nwas small. Here it is:\n\n```c\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n  int type=0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type= parse_stars(parse_type(&ctype, &class));\n    // Get the type's size\n    size= typesize(type, ctype);\n    rparen();\n    // Return a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, size));\n    ...\n  }\n  ...\n}\n```\n\nWe already have a `parse_type()` function to parse a type definition, and\nwe already have a `parse_stars()` function to parse any following asterisks.\nFinally, we already have a `typesize()` function which returns the number of\nbytes in a type. All we have to do is scan the tokens in, call these three\nfunctions, build a leaf AST node with an integer literal in it, and return it.\n\nYes, I know there are a bunch of subtleties that go with `sizeof()`, but\nI'm following the \"KISS principle\" and doing enough to make our compiler\nself-compiling.\n\n## Testing the New Code\n\nThe file `tests/input115.c` has a set of tests for the primitive types,\na pointer and for the structures in our compiler:\n\n```c\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n```\n\nAt present, the output from our compiler is:\n\n```\n1\n4\n8\n8\n13\n64\n48\n```\n\nI'm wondering if we need to pad the `struct foo` struct to be 16 bytes instead\nof 13. We'll cross that bridge when we get to it.\n\n## Conclusion and What's Next\n\nWell, `sizeof()` turned out to be simple, at least for the functionality that\nwe need for our compiler. In reality, `sizeof()` is quite complicated for\na full-blown production C compiler.\n\nIn the next part of our compiler writing journey, I will tackle `static`. [Next step](../48_Static/Readme.md)\n"
  },
  {
    "path": "47_Sizeof/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  fprintf(Outfile,\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\"\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name, name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->st_posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n  \n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i=0; i < node->nelems; i++) {\n  \n    // Get any initial value\n    initvalue= 0;\n    if (node->initlist != NULL)\n      initvalue= node->initlist[i];\n  \n    // Generate the space for this type\n    switch (size) {\n      case 1:\n        fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n        if (node->initlist != NULL && type== pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++)\n  \tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "47_Sizeof/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "47_Sizeof/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  fprintf(Outfile,\n\t  \"\\tglobal\\t%s\\n\"\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name, name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  fprintf(Outfile, \"\\tsection\\t.data\\n\" \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n  // Generate code depending on the function's type\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "47_Sizeof/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "47_Sizeof/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern (later, static)\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(void) {\n  int type, class;\n  struct symtable *ctype;\n\n  // Get the type inside the parentheses\n  type= parse_stars(parse_type(&ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return(type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree= optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type= tree->type;\n    tree= tree->left;\n  }\n\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return(tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue==0)\n      return(0);\n  }\n\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return(tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return(0);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym=NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree= NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym= addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym= addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym= addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym= addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, 0);\n      if (exprnode == NULL)\n        fatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode,\n\t\t\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t// New symbol table entry\n  int nelems= -1;\t// Assume the number of elements won't be given\n  int maxelems;\t\t// The maximum number of elements in the init list\n  int *initlist;\t// The list of initial elements \n  int i=0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems= parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class,\n\t\t  0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems= nelems;\n    else\n      maxelems= TABLE_INCREMENT;\n    initlist= (int *)malloc(maxelems *sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n        fatal(\"Too many values in initialisation list\");\n\n      initlist[i++]= parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n        maxelems += TABLE_INCREMENT;\n        initlist= (int *)realloc(initlist, maxelems *sizeof(int));\n      }\n\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n        scan(&Token);\n\tbreak;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j=i; j < sym->nelems; j++) initlist[j]=0;\n    if (i > nelems) nelems = i;\n    sym->initlist= initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  sym->nelems= nelems;\n  sym->size= sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n        paramcnt= 0; scan(&Token); break;\n      }\n    }\n\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, C_GLOBAL, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree= optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t= declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t== -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead==NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name= NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree= NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL)\n        fatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree== NULL)\n      *gluetree= tree;\n    else\n      *gluetree = mkastnode(A_GLUE, P_NONE, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "47_Sizeof/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(void);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "47_Sizeof/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\n  A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST,\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "47_Sizeof/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken) break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->st_posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n  int type=0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type= parse_stars(parse_type(&ctype, &class));\n    // Get the type's size\n    size= typesize(type, ctype);\n    rparen();\n    // Return a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    scan(&Token);\n\n\n    // If the token after is a type identifier, this is a cast expression\n    switch (Token.token) {\n      case T_IDENT:\n        // We have to see if the identifier matches a typedef.\n        // If not, treat it as an expression.\n        if (findtypedef(Text) == NULL) {\n          n = binexpr(0); break;\n        }\n      case T_VOID:\n      case T_CHAR:\n      case T_INT:\n      case T_LONG:\n      case T_STRUCT:\n      case T_UNION:\n      case T_ENUM:\n\t// Get the type inside the parentheses\n        type= parse_cast();\n        // Skip the closing ')' and then parse the following expression\n        rparen();\n\n      default: n = binexpr(0); // Scan in the expression\n    }\n\n    // We now have at least an expression in n, and possibly a non-zero type in type\n    // if there was a cast. Skip the closing ')' if there was no cast.\n    if (type == 0)\n      rparen();\n    else\n      // Otherwise, make a unary AST node for the cast\n      n= mkastunary(A_CAST, type, n, NULL, 0);\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n        tokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "47_Sizeof/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nint genlabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs();\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs();\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL) genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      if (n->right != NULL) genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->a_intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->a_intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n\tcase A_ASPLUS:\n\t  leftreg= cgadd(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n\tcase A_ASMINUS:\n\t  leftreg= cgsub(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n        case A_ASSTAR:\n\t  leftreg= cgmul(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n        case A_ASSLASH:\n\t  leftreg= cgdiv(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->a_size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (leftreg);\t\t// Not much to do\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "47_Sizeof/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "47_Sizeof/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "47_Sizeof/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "47_Sizeof/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "47_Sizeof/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "47_Sizeof/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "47_Sizeof/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "47_Sizeof/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "47_Sizeof/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix; posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token= 0;\t\t// and set there is no lookahead token\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "47_Sizeof/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "47_Sizeof/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "47_Sizeof/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return n;\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn hexchar();\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "47_Sizeof/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and get the compound expression\n\tmatch(T_COLON, \":\");\n\tleft= compound_statement(1); casecount++;\n\n\t// Build a sub-tree with the compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "47_Sizeof/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n"
  },
  {
    "path": "47_Sizeof/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input032.c",
    "content": "Unknown variable:cow on line 4 of input032.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input042.c",
    "content": "Undeclared function:fred on line 3 of input042.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input043.c",
    "content": "Undeclared array:b on line 3 of input043.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input044.c",
    "content": "Unknown variable:z on line 3 of input044.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input059.c",
    "content": "Undeclared variable:y on line 3 of input059.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input060.c",
    "content": "Undeclared variable:x on line 3 of input060.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input061.c",
    "content": "Undeclared variable:x on line 3 of input061.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input093.c",
    "content": "Unknown variable:fred on line 1 of input093.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "47_Sizeof/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "47_Sizeof/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "47_Sizeof/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "47_Sizeof/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "47_Sizeof/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "47_Sizeof/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "47_Sizeof/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "47_Sizeof/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "47_Sizeof/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "47_Sizeof/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "47_Sizeof/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "47_Sizeof/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "47_Sizeof/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "47_Sizeof/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "47_Sizeof/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "47_Sizeof/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "47_Sizeof/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "47_Sizeof/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "47_Sizeof/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "47_Sizeof/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "47_Sizeof/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "47_Sizeof/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "47_Sizeof/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "47_Sizeof/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "47_Sizeof/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "47_Sizeof/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "47_Sizeof/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "47_Sizeof/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "47_Sizeof/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "47_Sizeof/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "47_Sizeof/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "47_Sizeof/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "47_Sizeof/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "47_Sizeof/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "47_Sizeof/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "47_Sizeof/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "47_Sizeof/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "47_Sizeof/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "47_Sizeof/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "47_Sizeof/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "47_Sizeof/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "47_Sizeof/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "47_Sizeof/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "47_Sizeof/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "47_Sizeof/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "47_Sizeof/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "47_Sizeof/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "47_Sizeof/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "47_Sizeof/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "47_Sizeof/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "47_Sizeof/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "47_Sizeof/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "47_Sizeof/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "47_Sizeof/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "47_Sizeof/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "47_Sizeof/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "47_Sizeof/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "47_Sizeof/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "47_Sizeof/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "47_Sizeof/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "47_Sizeof/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "47_Sizeof/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "47_Sizeof/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "47_Sizeof/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "47_Sizeof/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "47_Sizeof/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "47_Sizeof/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "47_Sizeof/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "47_Sizeof/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "47_Sizeof/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "47_Sizeof/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "47_Sizeof/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "47_Sizeof/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "47_Sizeof/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "47_Sizeof/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "47_Sizeof/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "47_Sizeof/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "47_Sizeof/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "47_Sizeof/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "47_Sizeof/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "47_Sizeof/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "47_Sizeof/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "47_Sizeof/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "47_Sizeof/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "47_Sizeof/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "47_Sizeof/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "47_Sizeof/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "47_Sizeof/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "47_Sizeof/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "47_Sizeof/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "47_Sizeof/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "47_Sizeof/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "47_Sizeof/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "47_Sizeof/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "47_Sizeof/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "47_Sizeof/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "47_Sizeof/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "47_Sizeof/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int gendumplabel(void) {\n  static int id = 1;\n  return (id++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "47_Sizeof/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return(tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "48_Static/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "48_Static/Readme.md",
    "content": "# Part 48: A Subset of `static`\n\nIn a real C compiler, there are three types of `static` things:\n\n + static functions, whose declaration is visible only in the source\n   file where the function appears;\n + static global variables, whose declaration is visible only in the source\n   file where the variable appears; and\n + static local variables, which act like global variables except that\n   each static local variables is only visible within the function\n   where the variable appears.\n\nThe first two should be simple to implement:\n\n  + add them as a global variable when they are declared, and\n  + remove them from the global symbol table when that source code\n    file is closed\n\nThe third one is much harder. Here's an example. Let's keep two private counters\nwith functions to increment them:\n\n```c\nint inc_counter1(void) {\n  static int counter= 0;\n  return(counter);\n}\n\nint inc_counter2(void) {\n  static int counter= 0;\n  return(counter);\n}\n\n```\n\nBoth functions see their own `counter` variable, and the value of both\ncounters persist across function calls. The variable persistence makes\nthem \"global\" (i.e. live outside of function scope) but they are only\nvisible to one function, which makes them sort of \"local\".\n\nI'll drop a reference to\n[closures](https://en.wikipedia.org/wiki/Closure_(computer_programming))\nhere, but the theory side is a bit out of scope, mainly because I'm\n*not* going to implement this third type of static things.\n\nWhy not? Mainly because it will be hard to implement something that\nhas both global and local characteristics at the same time. But, also,\nI don't have any static local variables in our compiler (now that I've\nrewritten some code), and so there's no need for the functionality.\n\nInstead, we can concentrate on static global functions and static global\nvariables.\n\n## A New Keyword and Token\n\nWe have a new keyword `static` and a new token T_STATIC. As always,\nread through `scan.c` for the changes.\n\n## Parsing `static`\n\nThe `static` keyword gets parsed in the same place as `extern`. We also\nwant to reject any attempt to use the `static` keyword in a local context. So\nin `decl.c`, we modify `parse_type()`:\n\n```c\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n        if (*class == C_STATIC)\n          fatal(\"Illegal to have extern and static at the same time\");\n        *class = C_EXTERN;\n        scan(&Token);\n        break;\n      case T_STATIC:\n        if (*class == C_LOCAL)\n          fatal(\"Compiler doesn't support static local declarations\");\n        if (*class == C_EXTERN)\n          fatal(\"Illegal to have extern and static at the same time\");\n        *class = C_STATIC;\n        scan(&Token);\n        break;\n      default:\n        exstatic = 0;\n    }\n  }\n  ...\n}\n```\n\nIf we see either `static` or `extern`, we firstly check if this is\nlegal given the current declaration class. Then we update the `class`\nvariable. If we see neither tokens, we leave the loop.\n\nNow that we have a type which is marked as being for a static declaration,\nhow is this added to the global symbol table? We need to change, in\nnearly every place in the compiler, any use of the C_GLOBAL class to\nalso include C_STATIC. This occurs numerous times across multiple files,\nbut you should look out for code like this:\n\n```c\n    if (class == C_GLOBAL || class == C_STATIC) ...\n```\n\nin `cg.c`, `decl.c`, `expr.c` and `gen.c`.\n\n## Getting Rid of `static` Declarations\n\nOnce we have finished parsing static declarations, we need to remove them\nfrom the global symbol table. In `do_compile()` in `main.c`, just after\nwe close the input file, we now do this:\n\n```c\n  genpreamble();                // Output the preamble\n  global_declarations();        // Parse the global declarations\n  genpostamble();               // Output the postamble\n  fclose(Outfile);              // Close the output file\n  freestaticsyms();             // Free any static symbols in the file\n```\n\nSo let's now look at `freestaticsyms()` in `sym.c`. We walk the global symbol\ntable. For any static node, we relink the list to remove it. I'm not a whiz\nat linked list code, so I wrote out all the possibly alternatives on a sheet\nof paper to come up with the following code:\n\n```c\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev= NULL;\n\n  // Walk the global table looking for static entries\n  for (g= Globhead; g != NULL; g= g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL) prev->next= g->next;\n      else Globhead->next= g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n        if (prev != NULL) Globtail= prev;\n        else Globtail= Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev= g;\n}\n```\n\nThe overall effect is to treat static declarations as global declarations,\nbut to remove them from the symbol table at the end of processing an\ninput file.\n\n## Testing the Changes\n\nThere are three programs to test the changes, `tests/input116.c` through to\n`tests/input118.c`. Let's look at the first one:\n\n```c\n#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n```\n\nLet's look at the assembly output for some of this:\n\n```\n        ...\n        .data\ncounter:\n        .long   0\n        .text\nfred:\n        pushq   %rbp\n        movq    %rsp, %rbp\n        addq    $0,%rsp\n        ...\n```\n\nNormally, `counter` and `fred` would have been decorated with a `.globl`\nmarking. Now that they are static, they get labels but we tell the assembler\nnot to make these globally visible.\n\n## Conclusion and What's Next\n\nI was worried about `static`, but once I decided to not implement the really\nhard third alternative, it wasn't too bad. What caused me some grief was\ngoing through the code, finding all C_GLOBAL uses and ensuring that I added\nappropriate C_STATIC code as well.\n\nIn the next part of our compiler writing journey, I think it's time that\nI tackle the [ternary operator](https://en.wikipedia.org/wiki/%3F:). [Next step](../49_Ternary/Readme.md)\n"
  },
  {
    "path": "48_Static/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, @function\\n\", name, name);\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\"\n\t  \"\\tmovq\\t%%rsp, %%rbp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->st_posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n  \n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i=0; i < node->nelems; i++) {\n  \n    // Get any initial value\n    initvalue= 0;\n    if (node->initlist != NULL)\n      initvalue= node->initlist[i];\n  \n    // Generate the space for this type\n    switch (size) {\n      case 1:\n        fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n        if (node->initlist != NULL && type== pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++)\n  \tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Deal with pointers here as we can't put them in\n  // the switch statement\n  if (ptrtype(sym->type)) \n    fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  else {\n    // Generate code depending on the function's type\n    switch (sym->type) {\n      case P_CHAR:\n        fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n        break;\n      case P_INT:\n        fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n        break;\n      case P_LONG:\n        fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n        break;\n      default:\n        fatald(\"Bad function type in cgreturn:\", sym->type);\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "48_Static/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "48_Static/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", name);\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size= typesize(value_at(node->type), node->ctype);\n    type= value_at(node->type);\n  } else {\n    size = node->size;\n    type= node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Deal with pointers here as we can't put them in\n  // the switch statement\n  if (ptrtype(sym->type))\n    fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  else {\n    // Generate code depending on the function's type\n    switch (sym->type) {\n      case P_CHAR:\n        fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n        break;\n      case P_INT:\n        fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n        break;\n      case P_LONG:\n        fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n        break;\n      default:\n        fatald(\"Bad function type in cgreturn:\", sym->type);\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n"
  },
  {
    "path": "48_Static/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "48_Static/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(void) {\n  int type, class=0;\n  struct symtable *ctype;\n\n  // Get the type inside the parentheses\n  type= parse_stars(parse_type(&ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return(type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree= optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type= tree->type;\n    tree= tree->left;\n  }\n\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return(tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue==0)\n      return(0);\n  }\n\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return(tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return(0);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym=NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree= NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym= addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym= addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym= addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym= addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, 0);\n      if (exprnode == NULL)\n        fatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode,\n\t\t\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t// New symbol table entry\n  int nelems= -1;\t// Assume the number of elements won't be given\n  int maxelems;\t\t// The maximum number of elements in the init list\n  int *initlist;\t// The list of initial elements \n  int i=0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems= parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class,\n\t\t  0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems= nelems;\n    else\n      maxelems= TABLE_INCREMENT;\n    initlist= (int *)malloc(maxelems *sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n        fatal(\"Too many values in initialisation list\");\n\n      initlist[i++]= parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n        maxelems += TABLE_INCREMENT;\n        initlist= (int *)realloc(initlist, maxelems *sizeof(int));\n      }\n\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n        scan(&Token);\n\tbreak;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j=i; j < sym->nelems; j++) initlist[j]=0;\n    if (i > nelems) nelems = i;\n    sym->initlist= initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  sym->nelems= nelems;\n  sym->size= sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n        paramcnt= 0; scan(&Token); break;\n      }\n    }\n\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree= optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t= declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t== -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead==NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name= NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree= NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n        fatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree== NULL)\n      *gluetree= tree;\n    else\n      *gluetree = mkastnode(A_GLUE, P_NONE, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "48_Static/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs();\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nvoid freeall_registers(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(void);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "48_Static/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\n  A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "48_Static/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken) break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->st_posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n  int type=0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type= parse_stars(parse_type(&ctype, &class));\n    // Get the type's size\n    size= typesize(type, ctype);\n    rparen();\n    // Return a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    scan(&Token);\n\n\n    // If the token after is a type identifier, this is a cast expression\n    switch (Token.token) {\n      case T_IDENT:\n        // We have to see if the identifier matches a typedef.\n        // If not, treat it as an expression.\n        if (findtypedef(Text) == NULL) {\n          n = binexpr(0); break;\n        }\n      case T_VOID:\n      case T_CHAR:\n      case T_INT:\n      case T_LONG:\n      case T_STRUCT:\n      case T_UNION:\n      case T_ENUM:\n\t// Get the type inside the parentheses\n        type= parse_cast();\n        // Skip the closing ')' and then parse the following expression\n        rparen();\n\n      default: n = binexpr(0); // Scan in the expression\n    }\n\n    // We now have at least an expression in n, and possibly a non-zero type in type\n    // if there was a cast. Skip the closing ')' if there was no cast.\n    if (type == 0)\n      rparen();\n    else\n      // Otherwise, make a unary AST node for the cast\n      n= mkastunary(A_CAST, type, n, NULL, 0);\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    if (ASTop == A_ASSIGN) {\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n    } else {\n\n      // We are not doing an assignment, so both trees should be rvalues\n      // Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n        tokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "48_Static/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs();\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs();\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs();\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs();\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs();\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs();\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    genfreeregs();\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL) genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      if (n->right != NULL) genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs();\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, compare registers\n      // and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->a_intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->a_intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n\tcase A_ASPLUS:\n\t  leftreg= cgadd(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n\tcase A_ASMINUS:\n\t  leftreg= cgsub(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n        case A_ASSTAR:\n\t  leftreg= cgmul(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n        case A_ASSLASH:\n\t  leftreg= cgdiv(leftreg, rightreg);\n\t  n->right= n->left;\n\t  break;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL ||\n  \t      n->right->sym->class == C_STATIC)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->a_size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL || n->left->sym->class == C_STATIC)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (leftreg);\t\t// Not much to do\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs() {\n  freeall_registers();\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "48_Static/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "48_Static/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "48_Static/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "48_Static/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "48_Static/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "48_Static/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "48_Static/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "48_Static/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "48_Static/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix; posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token= 0;\t\t// and set there is no lookahead token\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "48_Static/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "48_Static/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "48_Static/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return n;\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn hexchar();\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "48_Static/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and get the compound expression\n\tmatch(T_COLON, \":\");\n\tleft= compound_statement(1); casecount++;\n\n\t// Build a sub-tree with the compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "48_Static/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev= NULL;\n\n  // Walk the global table looking for static entries\n  for (g= Globhead; g != NULL; g= g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL) prev->next= g->next;\n      else Globhead->next= g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n        if (prev != NULL) Globtail= prev;\n        else Globtail= Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev= g;\n}\n"
  },
  {
    "path": "48_Static/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "48_Static/tests/err.input032.c",
    "content": "Unknown variable:cow on line 4 of input032.c\n"
  },
  {
    "path": "48_Static/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "48_Static/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "48_Static/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "48_Static/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "48_Static/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "48_Static/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "48_Static/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "48_Static/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "48_Static/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "48_Static/tests/err.input042.c",
    "content": "Undeclared function:fred on line 3 of input042.c\n"
  },
  {
    "path": "48_Static/tests/err.input043.c",
    "content": "Undeclared array:b on line 3 of input043.c\n"
  },
  {
    "path": "48_Static/tests/err.input044.c",
    "content": "Unknown variable:z on line 3 of input044.c\n"
  },
  {
    "path": "48_Static/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "48_Static/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "48_Static/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "48_Static/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "48_Static/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "48_Static/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "48_Static/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "48_Static/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "48_Static/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "48_Static/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "48_Static/tests/err.input059.c",
    "content": "Undeclared variable:y on line 3 of input059.c\n"
  },
  {
    "path": "48_Static/tests/err.input060.c",
    "content": "Undeclared variable:x on line 3 of input060.c\n"
  },
  {
    "path": "48_Static/tests/err.input061.c",
    "content": "Undeclared variable:x on line 3 of input061.c\n"
  },
  {
    "path": "48_Static/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "48_Static/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "48_Static/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "48_Static/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "48_Static/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "48_Static/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "48_Static/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "48_Static/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "48_Static/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "48_Static/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "48_Static/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "48_Static/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "48_Static/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "48_Static/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "48_Static/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "48_Static/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "48_Static/tests/err.input093.c",
    "content": "Unknown variable:fred on line 1 of input093.c\n"
  },
  {
    "path": "48_Static/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "48_Static/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "48_Static/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "48_Static/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "48_Static/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "48_Static/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "48_Static/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "48_Static/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "48_Static/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "48_Static/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "48_Static/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "48_Static/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "48_Static/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "48_Static/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "48_Static/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "48_Static/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "48_Static/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "48_Static/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "48_Static/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "48_Static/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "48_Static/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "48_Static/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "48_Static/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "48_Static/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "48_Static/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "48_Static/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "48_Static/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "48_Static/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "48_Static/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "48_Static/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "48_Static/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "48_Static/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "48_Static/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "48_Static/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "48_Static/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "48_Static/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "48_Static/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "48_Static/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "48_Static/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "48_Static/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "48_Static/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "48_Static/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "48_Static/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "48_Static/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "48_Static/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "48_Static/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "48_Static/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "48_Static/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "48_Static/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "48_Static/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "48_Static/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "48_Static/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "48_Static/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "48_Static/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "48_Static/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "48_Static/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "48_Static/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "48_Static/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "48_Static/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "48_Static/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "48_Static/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "48_Static/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "48_Static/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "48_Static/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "48_Static/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "48_Static/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "48_Static/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "48_Static/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "48_Static/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "48_Static/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "48_Static/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "48_Static/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "48_Static/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "48_Static/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "48_Static/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "48_Static/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "48_Static/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "48_Static/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "48_Static/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "48_Static/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "48_Static/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "48_Static/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "48_Static/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "48_Static/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "48_Static/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "48_Static/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "48_Static/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "48_Static/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "48_Static/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "48_Static/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "48_Static/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "48_Static/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "48_Static/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "48_Static/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "48_Static/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "48_Static/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "48_Static/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "48_Static/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "48_Static/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "48_Static/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "48_Static/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "48_Static/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "48_Static/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "48_Static/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "48_Static/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "48_Static/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "48_Static/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "48_Static/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "48_Static/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "48_Static/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "48_Static/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "48_Static/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "48_Static/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "48_Static/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "48_Static/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "48_Static/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "48_Static/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "48_Static/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "48_Static/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "48_Static/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "48_Static/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "48_Static/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "48_Static/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "48_Static/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "48_Static/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "48_Static/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "48_Static/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "48_Static/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "48_Static/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "48_Static/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "48_Static/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "48_Static/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "48_Static/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "48_Static/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "48_Static/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "48_Static/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "48_Static/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "48_Static/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "48_Static/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "48_Static/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "48_Static/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "48_Static/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "48_Static/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "48_Static/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "48_Static/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "48_Static/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "48_Static/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "48_Static/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "48_Static/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return(tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "49_Ternary/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "49_Ternary/Readme.md",
    "content": "# Part 49: The Ternary Operator\n\nIn this part of our compiler writing journey, I've implemented the\n[ternary operator](https://en.wikipedia.org/wiki/%3F:). This is one\nof the really natty operators in the C language which can reduce\nlines of code in your source file. The basic syntax is:\n\n```\nternary_expression:\n        logical_expression '?' true_expression ':' false_expression\n        ;\n```\n\nWe evaluate the logical expression. If this is true, we then evaluate only\nthe true expression. Otherwise, we only evaluate the false expression.\nThe result of either the true or the false expression becomes the result\nof the whole expression.\n\nOne subtlety here is that, for example, in:\n\n```c\n   x= y != 5 ? y++ : ++y;\n```\n\nIf `y != 5` then `x= y++`, otherwise `x= ++y`. Either way, `y` is only\nincremented once.\n\nWe can rewrite the above code as an IF statement:\n\n```c\nif (y != 5)\n  x= y++;\nelse\n  x= ++y;\n```\n\nHowever, the ternary operator is an expression, so we can also do:\n\n```c\n  x= 23 * (y != 5 ? y++ : ++y) - 18;\n```\n\nThis can't be easily converted into an IF statement now. However, we can\nborrow some of the mechanics from the IF code generator to use for the\nternary operator.\n\n## Tokens, Operators and Operator Precedence\n\nWe already have ':' in our grammar as a token; now we need to add the '?'\ntoken. This is going to be treated as an operator, so we'd better set\nits precedence.\n\nAccording to [this list of C operators](https://en.cppreference.com/w/c/language/operator_precedence), the '?' operator has precedence just above the\nassignment operators.\n\nThe way we have designed our precedence, our operator tokens must be\nin precedence order and the AST operators must correspond to the tokens.\n\nThus, in `defs.h`, we now have:\n\n```c\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_QUESTION,                   // The '?' token\n  ...\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\n  A_TERNARY,                    // The ternary AST operator\n  ...\n```\n\nAnd in `expr.c`, we now have:\n\n```c\nstatic int OpPrec[] = {\n  0, 10, 10,                    // T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,                   // T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  15,                           // T_QUESTION\n  ...\n```\n\nAs always, I will leave you to browse the changes in `scan.c` for the\nnew T_QUESTION token.\n\n## Parsing the Ternary Operator\n\nEven though the ternary operator isn't a binary operator, because it\nhas precedence, we need to implement it in `binexpr()` with the binary\noperators. Here's the code:\n\n```c\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, ...\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp= binexpr(0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. XXX We should also\n      // consider the third expression's type.\n      return (mkastnode(A_TERNARY, right->type, left, right, ltemp, NULL, 0));\n      ...\n    }\n    ...\n}\n```\n\nWhen we hit the A_TERNARY case, we have the AST tree of the logical expression\nstored in `left`, the true expression in `right` and we have parsed the '?'\ntoken. Now we need to parse the ':' token and the false expression.\n\nWith all three tokens parsed, we can now build an AST node to hold all three.\nOne problem is how to determine the type of this node. As you can see, it's\neasy to choose the type of the middle token. To do it properly, I should\nsee, of the true and false expressions, which one is wider and choose that one.\nI'll leave it for now and revisit it.\n\n## Generating The Assembly Code: Issues\n\nGenerating the assembly code for the ternary operator is very similar to\nthat of the IF statement: we evaluate a logical expression. If true, we\nevaluate one expression; if false, we evaluate the other. We are going to\nneed some labels, and we are going to have to insert jumps to these labels\nas required.\n\nI did actually try to modify the `genIF()` code in `gen.c` to do both IF\nand the ternary operator, but it was easier just to write another function.\n\nThere is one wrinkle to the generation of the assembly code. Consider:\n\n```c\n   x= (y > 4) ? 2 * y - 18 : y * z - 3 * a;\n```\n\nWe have three expressions, and we need to allocate registers to evaluate\neach one. After the logical expression is evaluated and we have jumped to\nthe correct next section of code, we can free all the registers used in\nthe evaluation. For the true and false expressions, we can free all the\nregisters *except one*: the register holding the expression's rvalue.\n\nWe also can't predict which register this will be, because each expression\nhas different operands and operators; thus, the number of registers used\nwill differ, and the (last) register allocated to hold the result may be\ndifferent.\n\nBut we need to know which register does hold the result of both the true\nand false expressions, so when we jump to the code that will use this\nresult, it knows which register to access.\n\nThus, we need to do three things:\n\n  + allocate a register to hold the result *before* we run either the\n    true of false expression,\n  + copy the true and false expression result into this register, and\n  + free all registers *except* the register with the result.\n\n## Freeing Registers\n\nWe already have a function to free all registers, `freeall_registers()`,\nwhich takes no arguments. Our registers are numbered zero upwards. I've\nmodified this function to take, as an argument, the register we want to\n*keep*. And, in order to free *all* registers, we pass it NOREG which is defined to be the number `-1`:\n\n```c\n// Set all registers as available.\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n```\n\nThroughout the compiler, you will now see `freeall_registers(-1)` to\nreplace what used to be `freeall_registers()`.\n\n## Generating The Assembly Code\n\nWe now have a function in `gen.c` to deal with the ternary operator.\nIt gets called from the top of `genAST()`:\n\n```c\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n  ...\n  case A_TERNARY:\n    return (gen_ternary(n));\n```\n\nLet's have a look at the function in stages.\n\n```c\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(-1);\n```\n\nThis is pretty much exactly the same as the IF generating code. We pass the logical expression sub-tree, the\nfalse label and the A_TERNARY operator into `genAST()`. When `genAST()` sees\nthis, it knows to generate a jump if false to this label.\n\n```c\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n```\n\nWith the logical expression done, we can now allocate the register to\nhold both the true and false expression results. We call `genAST()` to\ngenerate the true expression code, and we get back the register with the\nresult. We now have to move this register's value into the known register.\nWith this done, we can free all registers except the known register. If\nwe did the true expression, we now jump to the end of the ternary\nassembly code.\n\n```c\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cglabel(Lend);\n  return (reg);\n}\n```\n\nAnd the code to evaluate the false expression is very similar. Either\nway, execution will get to the end label and, once we get here, we know\nthat the ternary result is in the known register.\n\n## Testing the New Code\n\nI was worried about nested ternary operators, which I've used quite a bit\nin other code. The ternary operator is *right associative*, which means\nwe bind the '?' to the right more tightly than to the left.\n\nFortunately, as we greedily seek out the ':' token and the false expression\nonce we have parsed the '?' token, our parser is already treating the\nternary operator as right associative.\n\n`tests/input121.c` is an example of a nested ternary operator:\n\n```c\n#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n```\n\nIf `y<4`, then `x` becomes `y+2`. If not, we evaluate the second ternary\noperator. If `y>7`, `x` becomes 1000, otherwise it becomes `y+9`.\n\nThe effect is to do `y+2` for `y` values 0 to 3, `y+9` for `y` values\n4 to 7, and 1000 for higher y values:\n\n```\n2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n```\n\n## Conclusion and What's Next\n\nLike a few of the steps so far, I was apprehensive to tackle the ternary\noperator because I thought it would be very difficult. I did have problems\nputting it into the IF generating code, so I stepped back a bit. Actually,\nI went out to see a movie with my wife and this gave me a chance to mull\nthings over. I realised that I had to free all but one registers, and I\nshould write a separate function. After that, writing the code was\nstraight forward. It's always good to step away from the keyboard now and\nthen.\n\nIn the next part of our compiler writing journey, I will feed the compiler\nto itself, look at the parse errors I get and choose one or more of them\nto fix.\n\n> P.S. We've reached 5,000 lines of code and 90,000 words in the Readme\nfiles. We must be nearly there! [Next step](../50_Mop_up_pt1/Readme.md)\n"
  },
  {
    "path": "49_Ternary/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n  case P_CHAR:\n    return (1);\n  case P_INT:\n    return (4);\n  case P_LONG:\n    return (8);\n  default:\n    fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n  case P_CHAR:\n    return (offset);\n  case P_INT:\n  case P_LONG:\n    break;\n  default:\n    if (!ptrtype(type))\n      fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\" \"\\t.type\\t%s, @function\\n\", name, name);\n  fprintf(Outfile, \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\" \"\\tmovq\\t%%rsp, %%rbp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->st_posn);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n      break;\n    case 8:\n      // Generate the pointer to a string literal. Treat a zero value\n      // as actually zero, not the label L0\n      if (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t  && initvalue != 0)\n\tfprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n      else\n\tfprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n      break;\n    default:\n      for (int i = 0; i < size; i++)\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Deal with pointers here as we can't put them in\n  // the switch statement\n  if (ptrtype(sym->type))\n    fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  else {\n    // Generate code depending on the function's type\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 2:\n    fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 4:\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  default:\n    fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n    break;\n  case 2:\n  case 4:\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n}\n"
  },
  {
    "path": "49_Ternary/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "49_Ternary/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", name);\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Deal with pointers here as we can't put them in\n  // the switch statement\n  if (ptrtype(sym->type))\n    fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  else {\n    // Generate code depending on the function's type\n    switch (sym->type) {\n      case P_CHAR:\n        fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n        break;\n      case P_INT:\n        fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n        break;\n      case P_LONG:\n        fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n        break;\n      default:\n        fatald(\"Bad function type in cgreturn:\", sym->type);\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n}\n"
  },
  {
    "path": "49_Ternary/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "49_Ternary/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(void) {\n  int type, class=0;\n  struct symtable *ctype;\n\n  // Get the type inside the parentheses\n  type= parse_stars(parse_type(&ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return(type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree= optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type= tree->type;\n    tree= tree->left;\n  }\n\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return(tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue==0)\n      return(0);\n  }\n\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return(tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return(0);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym=NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree= NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym= addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym= addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym= addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym= addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, 0);\n      if (exprnode == NULL)\n        fatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode,\n\t\t\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t// New symbol table entry\n  int nelems= -1;\t// Assume the number of elements won't be given\n  int maxelems;\t\t// The maximum number of elements in the init list\n  int *initlist;\t// The list of initial elements \n  int i=0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems= parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class,\n\t\t  0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems= nelems;\n    else\n      maxelems= TABLE_INCREMENT;\n    initlist= (int *)malloc(maxelems *sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n        fatal(\"Too many values in initialisation list\");\n\n      initlist[i++]= parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n        maxelems += TABLE_INCREMENT;\n        initlist= (int *)realloc(initlist, maxelems *sizeof(int));\n      }\n\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n        scan(&Token);\n\tbreak;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j=i; j < sym->nelems; j++) initlist[j]=0;\n    if (i > nelems) nelems = i;\n    sym->initlist= initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  sym->nelems= nelems;\n  sym->size= sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n        paramcnt= 0; scan(&Token); break;\n      }\n    }\n\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree= optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t= declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t== -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead==NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name= NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree= NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n        fatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree== NULL)\n      *gluetree= tree;\n    else\n      *gluetree = mkastnode(A_GLUE, P_NONE, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "49_Ternary/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nint alloc_register(void);\nvoid freeall_registers(int keepreg);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(void);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "49_Ternary/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_QUESTION, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\n  A_TERNARY, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "49_Ternary/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->st_posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n  int type = 0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type = parse_stars(parse_type(&ctype, &class));\n    // Get the type's size\n    size = typesize(type, ctype);\n    rparen();\n    // Return a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    scan(&Token);\n\n\n    // If the token after is a type identifier, this is a cast expression\n    switch (Token.token) {\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      if (findtypedef(Text) == NULL) {\n\tn = binexpr(0);\n\tbreak;\n      }\n    case T_VOID:\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n      // Get the type inside the parentheses\n      type = parse_cast();\n      // Skip the closing ')' and then parse the following expression\n      rparen();\n\n    default:\n      n = binexpr(0);\t\t// Scan in the expression\n    }\n\n    // We now have at least an expression in n, and possibly a non-zero type in type\n    // if there was a cast. Skip the closing ')' if there was no cast.\n    if (type == 0)\n      rparen();\n    else\n      // Otherwise, make a unary AST node for the cast\n      n = mkastunary(A_CAST, type, n, NULL, 0);\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp= binexpr(0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. XXX We should also\n      // consider the third expression's type.\n      return (mkastnode(A_TERNARY, right->type, left, right, ltemp, NULL, 0));\n\n    case A_ASSIGN:\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n      break;\n\n    default:\n      // We are not doing a ternary or assignment, so both trees should\n      // be rvalues. Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "49_Ternary/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs(reg);\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks\n    genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs(NOREG);\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    genfreeregs(NOREG);\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n  case A_IF:\n    return (genIF(n, looptoplabel, loopendlabel));\n  case A_WHILE:\n    return (genWHILE(n));\n  case A_SWITCH:\n    return (genSWITCH(n));\n  case A_FUNCCALL:\n    return (gen_funccall(n));\n  case A_TERNARY:\n    return (gen_ternary(n));\n  case A_GLUE:\n    // Do each child statement, and free the\n    // registers after each child\n    if (n->left != NULL)\n      genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    if (n->right != NULL)\n      genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    return (NOREG);\n  case A_FUNCTION:\n    // Generate the function's preamble before the code\n    // in the child sub-tree\n    cgfuncpreamble(n->sym);\n    genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n    cgfuncpostamble(n->sym);\n    return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n  case A_ADD:\n    return (cgadd(leftreg, rightreg));\n  case A_SUBTRACT:\n    return (cgsub(leftreg, rightreg));\n  case A_MULTIPLY:\n    return (cgmul(leftreg, rightreg));\n  case A_DIVIDE:\n    return (cgdiv(leftreg, rightreg));\n  case A_AND:\n    return (cgand(leftreg, rightreg));\n  case A_OR:\n    return (cgor(leftreg, rightreg));\n  case A_XOR:\n    return (cgxor(leftreg, rightreg));\n  case A_LSHIFT:\n    return (cgshl(leftreg, rightreg));\n  case A_RSHIFT:\n    return (cgshr(leftreg, rightreg));\n  case A_EQ:\n  case A_NE:\n  case A_LT:\n  case A_GT:\n  case A_LE:\n  case A_GE:\n    // If the parent AST node is an A_IF, A_WHILE or A_TERNARY,\n    // generate a compare followed by a jump. Otherwise, compare\n    // registers and set one to 1 or 0 based on the comparison.\n    if (parentASTop == A_IF || parentASTop == A_WHILE ||\n\tparentASTop == A_TERNARY)\n      return (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n    else\n      return (cgcompare_and_set(n->op, leftreg, rightreg));\n  case A_INTLIT:\n    return (cgloadint(n->a_intvalue, n->type));\n  case A_STRLIT:\n    return (cgloadglobstr(n->a_intvalue));\n  case A_IDENT:\n    // Load our value if we are an rvalue\n    // or we are being dereferenced\n    if (n->rvalue || parentASTop == A_DEREF) {\n      if (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC) {\n\treturn (cgloadglob(n->sym, n->op));\n      } else {\n\treturn (cgloadlocal(n->sym, n->op));\n      }\n    } else\n      return (NOREG);\n  case A_ASPLUS:\n  case A_ASMINUS:\n  case A_ASSTAR:\n  case A_ASSLASH:\n  case A_ASSIGN:\n\n    // For the '+=' and friends operators, generate suitable code\n    // and get the register with the result. Then take the left child,\n    // make it the right child so that we can fall into the assignment code.\n    switch (n->op) {\n    case A_ASPLUS:\n      leftreg = cgadd(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASMINUS:\n      leftreg = cgsub(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASSTAR:\n      leftreg = cgmul(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASSLASH:\n      leftreg = cgdiv(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    }\n\n    // Now into the assignment code\n    // Are we assigning to an identifier or through a pointer?\n    switch (n->right->op) {\n    case A_IDENT:\n      if (n->right->sym->class == C_GLOBAL ||\n\t  n->right->sym->class == C_STATIC)\n\treturn (cgstorglob(leftreg, n->right->sym));\n      else\n\treturn (cgstorlocal(leftreg, n->right->sym));\n    case A_DEREF:\n      return (cgstorderef(leftreg, rightreg, n->right->type));\n    default:\n      fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n    }\n  case A_WIDEN:\n    // Widen the child's type to the parent's type\n    return (cgwiden(leftreg, n->left->type, n->type));\n  case A_RETURN:\n    cgreturn(leftreg, Functionid);\n    return (NOREG);\n  case A_ADDR:\n    return (cgaddress(n->sym));\n  case A_DEREF:\n    // If we are an rvalue, dereference to get the value we point at,\n    // otherwise leave it for A_ASSIGN to store through the pointer\n    if (n->rvalue)\n      return (cgderef(leftreg, n->left->type));\n    else\n      return (leftreg);\n  case A_SCALE:\n    // Small optimisation: use shift if the\n    // scale value is a known power of two\n    switch (n->a_size) {\n    case 2:\n      return (cgshlconst(leftreg, 1));\n    case 4:\n      return (cgshlconst(leftreg, 2));\n    case 8:\n      return (cgshlconst(leftreg, 3));\n    default:\n      // Load a register with the size and\n      // multiply the leftreg by this size\n      rightreg = cgloadint(n->a_size, P_INT);\n      return (cgmul(leftreg, rightreg));\n    }\n  case A_POSTINC:\n  case A_POSTDEC:\n    // Load and decrement the variable's value into a register\n    // and post increment/decrement it\n    if (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC)\n      return (cgloadglob(n->sym, n->op));\n    else\n      return (cgloadlocal(n->sym, n->op));\n  case A_PREINC:\n  case A_PREDEC:\n    // Load and decrement the variable's value into a register\n    // and pre increment/decrement it\n    if (n->left->sym->class == C_GLOBAL || n->left->sym->class == C_STATIC)\n      return (cgloadglob(n->left->sym, n->op));\n    else\n      return (cgloadlocal(n->left->sym, n->op));\n  case A_NEGATE:\n    return (cgnegate(leftreg));\n  case A_INVERT:\n    return (cginvert(leftreg));\n  case A_LOGNOT:\n    return (cglognot(leftreg));\n  case A_TOBOOL:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, set the register\n    // to 0 or 1 based on it's zeroeness or non-zeroeness\n    return (cgboolean(leftreg, parentASTop, iflabel));\n  case A_BREAK:\n    cgjump(loopendlabel);\n    return (NOREG);\n  case A_CONTINUE:\n    cgjump(looptoplabel);\n    return (NOREG);\n  case A_CAST:\n    return (leftreg);\t\t// Not much to do\n  default:\n    fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs(int keepreg) {\n  freeall_registers(keepreg);\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "49_Ternary/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "49_Ternary/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "49_Ternary/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "49_Ternary/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "49_Ternary/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "49_Ternary/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "49_Ternary/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "49_Ternary/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "49_Ternary/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix; posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token= 0;\t\t// and set there is no lookahead token\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcST] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "49_Ternary/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "49_Ternary/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "49_Ternary/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return n;\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn hexchar();\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "49_Ternary/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *n, *c, *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and get the compound expression\n\tmatch(T_COLON, \":\");\n\tleft= compound_statement(1); casecount++;\n\n\t// Build a sub-tree with the compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "49_Ternary/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t \t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type== P_STRUCT || type== P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list, int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class==0 || class== list->class)\n        return (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead =   Globtail  =  NULL;\n  Loclhead =   Locltail  =  NULL;\n  Parmhead =   Parmtail  =  NULL;\n  Membhead =   Membtail  =  NULL;\n  Structhead = Structtail = NULL;\n  Unionhead =  Uniontail =  NULL;\n  Enumhead =   Enumtail =   NULL;\n  Typehead =   Typetail =   NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev= NULL;\n\n  // Walk the global table looking for static entries\n  for (g= Globhead; g != NULL; g= g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL) prev->next= g->next;\n      else Globhead->next= g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n        if (prev != NULL) Globtail= prev;\n        else Globtail= Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev= g;\n}\n"
  },
  {
    "path": "49_Ternary/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input032.c",
    "content": "Unknown variable:cow on line 4 of input032.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input042.c",
    "content": "Undeclared function:fred on line 3 of input042.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input043.c",
    "content": "Undeclared array:b on line 3 of input043.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input044.c",
    "content": "Unknown variable:z on line 3 of input044.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input059.c",
    "content": "Undeclared variable:y on line 3 of input059.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input060.c",
    "content": "Undeclared variable:x on line 3 of input060.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input061.c",
    "content": "Undeclared variable:x on line 3 of input061.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input093.c",
    "content": "Unknown variable:fred on line 1 of input093.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "49_Ternary/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "49_Ternary/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "49_Ternary/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "49_Ternary/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "49_Ternary/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "49_Ternary/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "49_Ternary/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "49_Ternary/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "49_Ternary/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "49_Ternary/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "49_Ternary/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "49_Ternary/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "49_Ternary/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "49_Ternary/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "49_Ternary/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "49_Ternary/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "49_Ternary/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "49_Ternary/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "49_Ternary/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "49_Ternary/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "49_Ternary/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "49_Ternary/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "49_Ternary/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "49_Ternary/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "49_Ternary/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "49_Ternary/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "49_Ternary/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "49_Ternary/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "49_Ternary/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "49_Ternary/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "49_Ternary/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "49_Ternary/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "49_Ternary/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "49_Ternary/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "49_Ternary/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "49_Ternary/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "49_Ternary/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "49_Ternary/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "49_Ternary/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "49_Ternary/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "49_Ternary/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "49_Ternary/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "49_Ternary/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "49_Ternary/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "49_Ternary/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "49_Ternary/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "49_Ternary/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "49_Ternary/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "49_Ternary/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "49_Ternary/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "49_Ternary/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "49_Ternary/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "49_Ternary/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "49_Ternary/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "49_Ternary/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "49_Ternary/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "49_Ternary/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "49_Ternary/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "49_Ternary/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "49_Ternary/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "49_Ternary/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "49_Ternary/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "49_Ternary/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "49_Ternary/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "49_Ternary/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "49_Ternary/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "49_Ternary/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "49_Ternary/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "49_Ternary/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "49_Ternary/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "49_Ternary/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "49_Ternary/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "49_Ternary/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "49_Ternary/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "49_Ternary/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "49_Ternary/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "49_Ternary/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "49_Ternary/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "49_Ternary/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "49_Ternary/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "49_Ternary/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "49_Ternary/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "49_Ternary/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "49_Ternary/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "49_Ternary/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "49_Ternary/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "49_Ternary/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "49_Ternary/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "49_Ternary/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "49_Ternary/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "49_Ternary/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "49_Ternary/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "49_Ternary/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "49_Ternary/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "49_Ternary/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "49_Ternary/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "49_Ternary/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "49_Ternary/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "49_Ternary/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "49_Ternary/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "49_Ternary/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "49_Ternary/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "49_Ternary/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "49_Ternary/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "49_Ternary/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "49_Ternary/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "49_Ternary/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "49_Ternary/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "49_Ternary/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "49_Ternary/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "49_Ternary/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "49_Ternary/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "49_Ternary/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "49_Ternary/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "49_Ternary/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "49_Ternary/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "49_Ternary/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "49_Ternary/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "49_Ternary/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "49_Ternary/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "49_Ternary/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "49_Ternary/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "49_Ternary/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "49_Ternary/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "49_Ternary/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "49_Ternary/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "49_Ternary/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "49_Ternary/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "49_Ternary/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return(tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "50_Mop_up_pt1/Readme.md",
    "content": "# Part 50: Mopping Up, part 1\n\nWe have definitely reached the \"mopping up\" phase, as in this part\nof our compiler writing journey I don't introduce any major feature.\nInstead, I fix a couple of problems and add a couple of minor\nfunctions.\n\n## Consecutive Cases\n\nAt present, the compiler can't parse\n\n```c\n  switch(x) {\n    case 1:\n    case 2: printf(\"Hello\\n\");\n  }\n```\n\nbecause the parser expects a compound statement after the ':' token.\nIn `switch_statement()` in `stmt.c`:\n\n```c\n        // Scan the ':' and get the compound expression\n        match(T_COLON, \":\");\n        left= compound_statement(1); casecount++;\n        ...\n        // Build a sub-tree with the compound statement as the left child\n        casetail->right= mkastunary(ASTop, 0, left, NULL, casevalue);\n```\n\nWhat we want is to allow an empty compound statement, so that any case\nwith a missing compound statement falls down into the next existing\ncompound statement.\n\nThe change in `switch_statement()` is:\n\n```c\n        // Scan the ':' and increment the casecount\n        match(T_COLON, \":\");\n        casecount++;\n\n        // If the next token is a T_CASE, the existing case will fall\n        // into the next case. Otherwise, parse the case body.\n        if (Token.token == T_CASE) \n          body= NULL;\n        else\n          body= compound_statement(1);\n```\n\nThis is, however, only half the story. Now in the code generation section,\nwe have to catch the NULL compound statement and do something about it.\nIn `genSWITCH()` in `gen.c`:\n\n```c\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n    ...\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    if (c->left) genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs(NOREG);\n  }\n```\n\nSo, this was a nice and simple fix. `tests/input123.c` is the test program\nto confirm this change works.\n\n## Dumping the Symbol Table\n\nWhile I was trying to work out why the global `Text` variable wasn't\nvisible to the compiler, I added code in `sym.c` to dump the symbol\ntable at the end of every source code file. There is an `-M` command\nline argument to enable the functionality. I won't go through the code,\nbut here is an example of its output:\n\n```\nSymbols for misc.c\nGlobal\n--------\nvoid exit(): global, 1 params\n    int status: param, size 4\nvoid _Exit(): global, 1 params\n    int status: param, size 4\nvoid *malloc(): global, 1 params\n    int size: param, size 4\n...\nint Line: extern, size 4\nint Putback: extern, size 4\nstruct symtable *Functionid: extern, size 8\nchar **Infile: extern, size 8\nchar **Outfile: extern, size 8\nchar *Text[]: extern, 513 elems, size 513\nstruct symtable *Globhead: extern, size 8\nstruct symtable *Globtail: extern, size 8\n...\nstruct mkastleaf *mkastleaf(): global, 4 params\n    int op: param, size 4\n    int type: param, size 4\n    struct symtable *sym: param, size 8\n    int intvalue: param, size 4\n...\nEnums\n--------\nint (null): enumtype, size 0\nint TEXTLEN: enumval, value 512\nint (null): enumtype, size 0\nint T_EOF: enumval, value 0\nint T_ASSIGN: enumval, value 1\nint T_ASPLUS: enumval, value 2\nint T_ASMINUS: enumval, value 3\nint T_ASSTAR: enumval, value 4\nint T_ASSLASH: enumval, value 5\n...\nTypedefs\n--------\nlong size_t: typedef, size 0\nchar *FILE: typedef, size 0\n```\n\n## Passing Arrays as Arguments\n\nI made the following change, but in hindsight I realise that I probably \nneed to rethink how I deal with arrays completely. Anyway ... when I\ncompile `decl.c` with the compiler, I get the error:\n\n```\nUnknown variable:Text on line 87 of decl.c\n```\n\nwhich prompted me to write the symbol dumping code. `Text` is in the global\nsymbol table, so why is the parser complaining that it's missing?\n\nThe answer is that `postfix()` in `expr.c`, after finding an identifier,\nconsults the following token. If it is a '[', then the identifier must\nbe an array. If there is no '[', then the identifier must be a variable:\n\n```c\n  // A variable. Check that the variable exists.\n  if ((varptr = findsymbol(Text)) == NULL || varptr->stype != S_VARIABLE)\n    fatals(\"Unknown variable\", Text);\n```\n\nThis is preventing the passing of an array reference as an argument to a\nfunction. The \"offending\" line that prompts the error message is in `decl.c`:\n\n```c\n      type = type_of_typedef(Text, ctype);\n```\n\nWe are passing the address of the base of `Text` as an argument. But with\nno following '[', our compiler thinks that it's a scalar variable, and\ncomplains that there is no scalar variable `Text`.\n\nI made the change to allow S_ARRAY as well as S_VARIABLE here, but this is\njust the tip of a bigger problem: arrays and pointers in our compiler are\nnot as interchangeable as they should be. I'll tackle this in the next part.\n\n## Missing Operators\n\nIn our compiler, we've had these tokens and AST operators since part 21\nof the journey:\n\n + <code>&#124;&#124;</code>, T_LOGOR, A_LOGOR\n + `&&`, T_LOGAND, A_LOGAND\n\nSomehow, I'd never implemented them! So, it's time to do them.\n\nFor A_LOGAND, we have two expressions. If both evaluate to true, we need to\nset a register to the rvalue of 1, otherwise 0. For A_LOGOR, if either\nevaluate to true, we need to set a register to the rvalue of 1, otherwise 0.\n\nThe `binexpr()` code in `expr.c` already parses the tokens and builds the\nA_LOGOR and A_LOGAND AST nodes. So we need to fix up the code generator.\n\nIn `genAST()` in `gen.c`, we now have:\n\n```c\n  case A_LOGOR:\n    return (cglogor(leftreg, rightreg));\n  case A_LOGAND:\n    return (cglogand(leftreg, rightreg));\n```\n\nwith two corresponding functions in `cg.c`. Before we look at the `cg.c`\nfunctions, let's just see an example C expression and the assembly code\nthat will be produced.\n\n```c\nint x, y, z;\n  ...\n  z= x || y;\n```\n\nwhen compiled, results in:\n\n```\n        movslq  x(%rip), %r10           # Load x's rvalue\n        movslq  y(%rip), %r11           # Load y's rvalue\n        test    %r10, %r10              # Test x's boolean value\n        jne     L13                     # True, jump to L13\n        test    %r11, %r11              # Test y's boolean value\n        jne     L13                     # True, jump to L13\n        movq    $0, %r10                # Neither true, set %r10 to false\n        jmp     L14                     # and jump to L14\nL13:\n        movq    $1, %r10                # Set %r10 to true\nL14:\n        movl    %r10d, z(%rip)          # Save boolean result to z\n```\n\nWe test each expression, jump based on the boolean result and either\nstore 0 or 1 into our output register. The assembly for A_LOGAND is\nsimilar, except that the conditional jumps are `je` (jump if equal to zero)\nand the `movq $0` and `movq $1` are swapped around.\n\nSo, without further comment, are the new `cg.c` functions:\n\n```c\n// Logically OR two registers and return a\n// register with the result, 1 or 0\nint cglogor(int r1, int r2) {\n  // Generate two labels\n  int Ltrue = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Test r2 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Didn't jump, so result is false\n  fprintf(Outfile, \"\\tmovq\\t$0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the true label, so result is true\n  cglabel(Ltrue);\n  fprintf(Outfile, \"\\tmovq\\t$1, %s\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n```\n\n```c\n// Logically AND two registers and return a\n// register with the result, 1 or 0\nint cglogand(int r1, int r2) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Test r2 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Didn't jump, so result is true\n  fprintf(Outfile, \"\\tmovq\\t$1, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the false label, so result is false\n  cglabel(Lfalse);\n  fprintf(Outfile, \"\\tmovq\\t$0, %s\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n```\n\nThe program `tests/input122.c` is the test to confirm that this new\nfunctionality works.\n\n## Conclusion and What's Next\n\nSo that's a few small things fixed up in this part of our journey.\nWhat I will do now is step back, rethink the array/pointer design and\ntry to fix this up in the next part of our compiler writing journey. [Next step](../51_Arrays_pt2/Readme.md)\n"
  },
  {
    "path": "50_Mop_up_pt1/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n  case P_CHAR:\n    return (1);\n  case P_INT:\n    return (4);\n  case P_LONG:\n    return (8);\n  default:\n    fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n  case P_CHAR:\n    return (offset);\n  case P_INT:\n  case P_LONG:\n    break;\n  default:\n    if (!ptrtype(type))\n      fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\" \"\\t.type\\t%s, @function\\n\", name, name);\n  fprintf(Outfile, \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\" \"\\tmovq\\t%%rsp, %%rbp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Logically OR two registers and return a\n// register with the result, 1 or 0\nint cglogor(int r1, int r2) {\n  // Generate two labels\n  int Ltrue = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Test r2 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Didn't jump, so result is false\n  fprintf(Outfile, \"\\tmovq\\t$0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the true label, so result is true\n  cglabel(Ltrue);\n  fprintf(Outfile, \"\\tmovq\\t$1, %s\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n\n// Logically AND two registers and return a\n// register with the result, 1 or 0\nint cglogand(int r1, int r2) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Test r2 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Didn't jump, so result is true\n  fprintf(Outfile, \"\\tmovq\\t$1, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the false label, so result is false\n  cglabel(Lfalse);\n  fprintf(Outfile, \"\\tmovq\\t$0, %s\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->st_posn);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n      break;\n    case 8:\n      // Generate the pointer to a string literal. Treat a zero value\n      // as actually zero, not the label L0\n      if (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t  && initvalue != 0)\n\tfprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n      else\n\tfprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n      break;\n    default:\n      for (int i = 0; i < size; i++)\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Deal with pointers here as we can't put them in\n  // the switch statement\n  if (ptrtype(sym->type))\n    fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  else {\n    // Generate code depending on the function's type\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 2:\n    fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 4:\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  default:\n    fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n    break;\n  case 2:\n  case 4:\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  for (int i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", name);\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Logically OR two registers and return a\n// register with the result, 1 or 0\nint cglogor(int r1, int r2) {\n  // Generate two labels\n  int Ltrue = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Test r2 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Didn't jump, so result is false\n  fprintf(Outfile, \"\\tmov\\t%s, 0\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the true label, so result is true\n  cglabel(Ltrue);\n  fprintf(Outfile, \"\\tmov\\t%s, 1\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n\n// Logically AND two registers and return a\n// register with the result, 1 or 0\nint cglogand(int r1, int r2) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Test r2 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Didn't jump, so result is true\n  fprintf(Outfile, \"\\tmov\\t%s, 1\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the false label, so result is false\n  cglabel(Lfalse);\n  fprintf(Outfile, \"\\tmov\\t%s, 0\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Deal with pointers here as we can't put them in\n  // the switch statement\n  if (ptrtype(sym->type))\n    fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  else {\n    // Generate code depending on the function's type\n    switch (sym->type) {\n      case P_CHAR:\n        fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n        break;\n      case P_INT:\n        fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n        break;\n      case P_LONG:\n        fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n        break;\n      default:\n        fatald(\"Bad function type in cgreturn:\", sym->type);\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_dumpsym;\t\t// If true, dump the symbol table\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "50_Mop_up_pt1/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(void) {\n  int type, class=0;\n  struct symtable *ctype;\n\n  // Get the type inside the parentheses\n  type= parse_stars(parse_type(&ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return(type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree= optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type= tree->type;\n    tree= tree->left;\n  }\n\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return(tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue==0)\n      return(0);\n  }\n\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return(tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return(0);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym=NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree= NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym= addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym= addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym= addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym= addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, 0);\n      if (exprnode == NULL)\n        fatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode,\n\t\t\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t// New symbol table entry\n  int nelems= -1;\t// Assume the number of elements won't be given\n  int maxelems;\t\t// The maximum number of elements in the init list\n  int *initlist;\t// The list of initial elements \n  int i=0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems= parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class,\n\t\t  0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems= nelems;\n    else\n      maxelems= TABLE_INCREMENT;\n    initlist= (int *)malloc(maxelems *sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n        fatal(\"Too many values in initialisation list\");\n\n      initlist[i++]= parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n        maxelems += TABLE_INCREMENT;\n        initlist= (int *)realloc(initlist, maxelems *sizeof(int));\n      }\n\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n        scan(&Token);\n\tbreak;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j=i; j < sym->nelems; j++) initlist[j]=0;\n    if (i > nelems) nelems = i;\n    sym->initlist= initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  sym->nelems= nelems;\n  sym->size= sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n        paramcnt= 0; scan(&Token); break;\n      }\n    }\n\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree= optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t= declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t== -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead==NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name= NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree= NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n        fatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree== NULL)\n      *gluetree= tree;\n    else\n      *gluetree = mkastnode(A_GLUE, P_NONE, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nint alloc_register(void);\nvoid freeall_registers(int keepreg);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cglogor(int r1, int r2);\nint cglogand(int r1, int r2);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\nvoid dumptable(struct symtable *head, char *name, int indent);\nvoid dumpsymtables(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(void);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "50_Mop_up_pt1/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_QUESTION, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\n  A_TERNARY, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "50_Mop_up_pt1/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array\n  // then make a leaf node for it that points at the base\n  if ((aryptr = findsymbol(Text)) == NULL || aryptr->stype != S_ARRAY) {\n    fatals(\"Undeclared array\", Text);\n  }\n  left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->st_posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // A variable or name of an array. Check that it exists.\n  if ((varptr = findsymbol(Text)) == NULL ||\n      (varptr->stype != S_VARIABLE && varptr->stype != S_ARRAY)) {\n    fatals(\"Unknown variable\", Text);\n  }\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference\n  default:\n    n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n  int type = 0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type = parse_stars(parse_type(&ctype, &class));\n    // Get the type's size\n    size = typesize(type, ctype);\n    rparen();\n    // Return a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    scan(&Token);\n\n\n    // If the token after is a type identifier, this is a cast expression\n    switch (Token.token) {\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      if (findtypedef(Text) == NULL) {\n\tn = binexpr(0);\n\tbreak;\n      }\n    case T_VOID:\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n      // Get the type inside the parentheses\n      type = parse_cast();\n      // Skip the closing ')' and then parse the following expression\n      rparen();\n\n    default:\n      n = binexpr(0);\t\t// Scan in the expression\n    }\n\n    // We now have at least an expression in n, and possibly a non-zero type in type\n    // if there was a cast. Skip the closing ')' if there was no cast.\n    if (type == 0)\n      rparen();\n    else\n      // Otherwise, make a unary AST node for the cast\n      n = mkastunary(A_CAST, type, n, NULL, 0);\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp= binexpr(0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. XXX We should also\n      // consider the third expression's type.\n      return (mkastnode(A_TERNARY, right->type, left, right, ltemp, NULL, 0));\n\n    case A_ASSIGN:\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n      break;\n\n    default:\n      // We are not doing a ternary or assignment, so both trees should\n      // be rvalues. Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs(reg);\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    if (c->left) genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs(NOREG);\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    genfreeregs(NOREG);\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n  case A_IF:\n    return (genIF(n, looptoplabel, loopendlabel));\n  case A_WHILE:\n    return (genWHILE(n));\n  case A_SWITCH:\n    return (genSWITCH(n));\n  case A_FUNCCALL:\n    return (gen_funccall(n));\n  case A_TERNARY:\n    return (gen_ternary(n));\n  case A_GLUE:\n    // Do each child statement, and free the\n    // registers after each child\n    if (n->left != NULL)\n      genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    if (n->right != NULL)\n      genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    return (NOREG);\n  case A_FUNCTION:\n    // Generate the function's preamble before the code\n    // in the child sub-tree\n    cgfuncpreamble(n->sym);\n    genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n    cgfuncpostamble(n->sym);\n    return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n  case A_ADD:\n    return (cgadd(leftreg, rightreg));\n  case A_SUBTRACT:\n    return (cgsub(leftreg, rightreg));\n  case A_MULTIPLY:\n    return (cgmul(leftreg, rightreg));\n  case A_DIVIDE:\n    return (cgdiv(leftreg, rightreg));\n  case A_AND:\n    return (cgand(leftreg, rightreg));\n  case A_OR:\n    return (cgor(leftreg, rightreg));\n  case A_XOR:\n    return (cgxor(leftreg, rightreg));\n  case A_LSHIFT:\n    return (cgshl(leftreg, rightreg));\n  case A_RSHIFT:\n    return (cgshr(leftreg, rightreg));\n  case A_EQ:\n  case A_NE:\n  case A_LT:\n  case A_GT:\n  case A_LE:\n  case A_GE:\n    // If the parent AST node is an A_IF, A_WHILE or A_TERNARY,\n    // generate a compare followed by a jump. Otherwise, compare\n    // registers and set one to 1 or 0 based on the comparison.\n    if (parentASTop == A_IF || parentASTop == A_WHILE ||\n\tparentASTop == A_TERNARY)\n      return (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n    else\n      return (cgcompare_and_set(n->op, leftreg, rightreg));\n  case A_INTLIT:\n    return (cgloadint(n->a_intvalue, n->type));\n  case A_STRLIT:\n    return (cgloadglobstr(n->a_intvalue));\n  case A_IDENT:\n    // Load our value if we are an rvalue\n    // or we are being dereferenced\n    if (n->rvalue || parentASTop == A_DEREF) {\n      if (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC) {\n\treturn (cgloadglob(n->sym, n->op));\n      } else {\n\treturn (cgloadlocal(n->sym, n->op));\n      }\n    } else\n      return (NOREG);\n  case A_ASPLUS:\n  case A_ASMINUS:\n  case A_ASSTAR:\n  case A_ASSLASH:\n  case A_ASSIGN:\n\n    // For the '+=' and friends operators, generate suitable code\n    // and get the register with the result. Then take the left child,\n    // make it the right child so that we can fall into the assignment code.\n    switch (n->op) {\n    case A_ASPLUS:\n      leftreg = cgadd(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASMINUS:\n      leftreg = cgsub(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASSTAR:\n      leftreg = cgmul(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASSLASH:\n      leftreg = cgdiv(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    }\n\n    // Now into the assignment code\n    // Are we assigning to an identifier or through a pointer?\n    switch (n->right->op) {\n    case A_IDENT:\n      if (n->right->sym->class == C_GLOBAL ||\n\t  n->right->sym->class == C_STATIC)\n\treturn (cgstorglob(leftreg, n->right->sym));\n      else\n\treturn (cgstorlocal(leftreg, n->right->sym));\n    case A_DEREF:\n      return (cgstorderef(leftreg, rightreg, n->right->type));\n    default:\n      fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n    }\n  case A_WIDEN:\n    // Widen the child's type to the parent's type\n    return (cgwiden(leftreg, n->left->type, n->type));\n  case A_RETURN:\n    cgreturn(leftreg, Functionid);\n    return (NOREG);\n  case A_ADDR:\n    return (cgaddress(n->sym));\n  case A_DEREF:\n    // If we are an rvalue, dereference to get the value we point at,\n    // otherwise leave it for A_ASSIGN to store through the pointer\n    if (n->rvalue)\n      return (cgderef(leftreg, n->left->type));\n    else\n      return (leftreg);\n  case A_SCALE:\n    // Small optimisation: use shift if the\n    // scale value is a known power of two\n    switch (n->a_size) {\n    case 2:\n      return (cgshlconst(leftreg, 1));\n    case 4:\n      return (cgshlconst(leftreg, 2));\n    case 8:\n      return (cgshlconst(leftreg, 3));\n    default:\n      // Load a register with the size and\n      // multiply the leftreg by this size\n      rightreg = cgloadint(n->a_size, P_INT);\n      return (cgmul(leftreg, rightreg));\n    }\n  case A_POSTINC:\n  case A_POSTDEC:\n    // Load and decrement the variable's value into a register\n    // and post increment/decrement it\n    if (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC)\n      return (cgloadglob(n->sym, n->op));\n    else\n      return (cgloadlocal(n->sym, n->op));\n  case A_PREINC:\n  case A_PREDEC:\n    // Load and decrement the variable's value into a register\n    // and pre increment/decrement it\n    if (n->left->sym->class == C_GLOBAL || n->left->sym->class == C_STATIC)\n      return (cgloadglob(n->left->sym, n->op));\n    else\n      return (cgloadlocal(n->left->sym, n->op));\n  case A_NEGATE:\n    return (cgnegate(leftreg));\n  case A_INVERT:\n    return (cginvert(leftreg));\n  case A_LOGNOT:\n    return (cglognot(leftreg));\n  case A_LOGOR:\n    return (cglogor(leftreg, rightreg));\n  case A_LOGAND:\n    return (cglogand(leftreg, rightreg));\n  case A_TOBOOL:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, set the register\n    // to 0 or 1 based on it's zeroeness or non-zeroeness\n    return (cgboolean(leftreg, parentASTop, iflabel));\n  case A_BREAK:\n    cgjump(loopendlabel);\n    return (NOREG);\n  case A_CONTINUE:\n    cgjump(looptoplabel);\n    return (NOREG);\n  case A_CAST:\n    return (leftreg);\t\t// Not much to do\n  default:\n    fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs(int keepreg) {\n  freeall_registers(keepreg);\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "50_Mop_up_pt1/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "50_Mop_up_pt1/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "50_Mop_up_pt1/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "50_Mop_up_pt1/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "50_Mop_up_pt1/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "50_Mop_up_pt1/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "50_Mop_up_pt1/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "50_Mop_up_pt1/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix; posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token= 0;\t\t// and set there is no lookahead token\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n\n  // Dump the symbol table if requested\n  if (O_dumpsym) {\n    printf(\"Symbols for %s\\n\", filename);\n    dumpsymtables();\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcSTM] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -M dump the symbol table for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_dumpsym = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'M':\n\t  O_dumpsym = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return n;\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn hexchar();\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *body, *n, *c;\n  struct ASTnode *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and increment the casecount\n\tmatch(T_COLON, \":\");\n\tcasecount++;\n\n\t// If the next token is a T_CASE, the existing case will fall\n\t// into the next case. Otherwise, parse the case body.\n\tif (Token.token == T_CASE) \n\t  body= NULL;\n\telse\n\t  body= compound_statement(1);\n\n\t// Build a sub-tree with any compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, body, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, body, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list,\n\t\t\t\t      int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class == 0 || class == list->class)\n\treturn (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead = Globtail = NULL;\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Membhead = Membtail = NULL;\n  Structhead = Structtail = NULL;\n  Unionhead = Uniontail = NULL;\n  Enumhead = Enumtail = NULL;\n  Typehead = Typetail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev = NULL;\n\n  // Walk the global table looking for static entries\n  for (g = Globhead; g != NULL; g = g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL)\n\tprev->next = g->next;\n      else\n\tGlobhead->next = g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n\tif (prev != NULL)\n\t  Globtail = prev;\n\telse\n\t  Globtail = Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev = g;\n}\n\n// Dump a single symbol\nstatic void dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n  case P_VOID:\n    printf(\"void \");\n    break;\n  case P_CHAR:\n    printf(\"char \");\n    break;\n  case P_INT:\n    printf(\"int \");\n    break;\n  case P_LONG:\n    printf(\"long \");\n    break;\n  case P_STRUCT:\n    if (sym->ctype != NULL)\n      printf(\"struct %s \", sym->ctype->name);\n    else\n      printf(\"struct %s \", sym->name);\n    break;\n  case P_UNION:\n    if (sym->ctype != NULL)\n      printf(\"union %s \", sym->ctype->name);\n    else\n      printf(\"union %s \", sym->name);\n    break;\n  default:\n    printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++)\n    printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n  case S_VARIABLE:\n    break;\n  case S_FUNCTION:\n    printf(\"()\");\n    break;\n  case S_ARRAY:\n    printf(\"[]\");\n    break;\n  default:\n    printf(\" unknown stype\");\n  }\n\n  switch (sym->class) {\n  case C_GLOBAL:\n    printf(\": global\");\n    break;\n  case C_LOCAL:\n    printf(\": local\");\n    break;\n  case C_PARAM:\n    printf(\": param\");\n    break;\n  case C_EXTERN:\n    printf(\": extern\");\n    break;\n  case C_STATIC:\n    printf(\": static\");\n    break;\n  case C_STRUCT:\n    printf(\": struct\");\n    break;\n  case C_UNION:\n    printf(\": union\");\n    break;\n  case C_MEMBER:\n    printf(\": member\");\n    break;\n  case C_ENUMTYPE:\n    printf(\": enumtype\");\n    break;\n  case C_ENUMVAL:\n    printf(\": enumval\");\n    break;\n  case C_TYPEDEF:\n    printf(\": typedef\");\n    break;\n  default:\n    printf(\": unknown class\");\n  }\n\n  switch (sym->stype) {\n  case S_VARIABLE:\n    if (sym->class == C_ENUMVAL)\n      printf(\", value %d\\n\", sym->st_posn);\n    else\n      printf(\", size %d\\n\", sym->size);\n    break;\n  case S_FUNCTION:\n    printf(\", %d params\\n\", sym->nelems);\n    break;\n  case S_ARRAY:\n    printf(\", %d elems, size %d\\n\", sym->nelems, sym->size);\n    break;\n  }\n\n  switch (sym->type & (~0xf)) {\n  case P_STRUCT:\n  case P_UNION:\n    dumptable(sym->member, NULL, 4);\n  }\n\n  switch (sym->stype) {\n  case S_FUNCTION:\n    dumptable(sym->member, NULL, 4);\n  }\n}\n\n// Dump one symbol table\nvoid dumptable(struct symtable *head, char *name, int indent) {\n  struct symtable *sym;\n\n  if (head != NULL && name != NULL)\n    printf(\"%s\\n--------\\n\", name);\n  for (sym = head; sym != NULL; sym = sym->next)\n    dumpsym(sym, indent);\n}\n\nvoid dumpsymtables(void) {\n  dumptable(Globhead, \"Global\", 0);\n  printf(\"\\n\");\n  dumptable(Enumhead, \"Enums\", 0);\n  printf(\"\\n\");\n  dumptable(Typehead, \"Typedefs\", 0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input032.c",
    "content": "Unknown variable:cow on line 4 of input032.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input042.c",
    "content": "Undeclared function:fred on line 3 of input042.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input043.c",
    "content": "Undeclared array:b on line 3 of input043.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input044.c",
    "content": "Unknown variable:z on line 3 of input044.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input059.c",
    "content": "Undeclared variable:y on line 3 of input059.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input060.c",
    "content": "Undeclared variable:x on line 3 of input060.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input061.c",
    "content": "Undeclared variable:x on line 3 of input061.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input093.c",
    "content": "Unknown variable:fred on line 1 of input093.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input122.c",
    "content": "#include <stdio.h>\n\nint x, y, z1, z2;\n\nint main() {\n  for (x= 0; x <= 1; x++) {\n    for (y= 0; y <= 1; y++) {\n      z1= x || y; z2= x && y;\n      printf(\"x %d, y %d, x || y %d, x && y %d\\n\", x, y, z1, z2);\n    }\n  }\n  \n  //z= x || y;\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/input123.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  for (x=0; x < 20; x++)\n    switch(x) {\n      case 2:\n      case 3:\n      case 5:\n      case 7:\n      case 11: printf(\"%2d infant prime\\n\", x); break;\n      case 13:\n      case 17:\n      case 19: printf(\"%2d teen   prime\\n\", x); break;\n      case 0:\n      case 1:\n      case 4:\n      case 6:\n      case 8:\n      case 9:\n      case 10:\n      case 12: printf(\"%2d infant composite\\n\", x); break;\n      default: printf(\"%2d teen   composite\\n\", x); break;\n    }\n\n  return(0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input122.c",
    "content": "x 0, y 0, x || y 0, x && y 0\nx 0, y 1, x || y 1, x && y 0\nx 1, y 0, x || y 1, x && y 0\nx 1, y 1, x || y 1, x && y 1\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/out.input123.c",
    "content": " 0 infant composite\n 1 infant composite\n 2 infant prime\n 3 infant prime\n 4 infant composite\n 5 infant prime\n 6 infant composite\n 7 infant prime\n 8 infant composite\n 9 infant composite\n10 infant composite\n11 infant prime\n12 infant composite\n13 teen   prime\n14 teen   composite\n15 teen   composite\n16 teen   composite\n17 teen   prime\n18 teen   composite\n19 teen   prime\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "50_Mop_up_pt1/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "50_Mop_up_pt1/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "50_Mop_up_pt1/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return(tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "51_Arrays_pt2/Readme.md",
    "content": "# Part 51: Arrays, part 2\n\nIn the last part of our compiler writing journey, I realised that I\nhad implemented arrays not exactly right. In this part of our compiler\nwriting journey, I'll try to rectify things.\n\nTo start with, I stepped back and thought a bit about arrays and pointers.\nI realised that an array is similar to a pointer except:\n\n  1. You can't use the unadorned array identifier as an rvalue.\n  2. The size of an array is the size of all of its elements.\n     The size of a pointer does not include the elements of\n     any array that it points to.\n  3. The address of an array (e.g. `&ary`) doesn't mean anything\n     useful, unlike the address of a pointer (e.g. `&ptr`).\n\nAs an example of the first point above, consider:\n\n```c\nint ary[5];\nint *ptr;\n\nint main() {\n   ptr= ary;            // OK, put base address of ary into ptr\n   ary= ptr;            // Bad, can't change ary's base address\n```\n\nAnd, for those C purists out there, yes I know that point 3 isn't\nentirely true. But I'm not going to use `&ary` anywhere, so I can\nget our compiler to reject it, and that means I won't need to\nimplement this functionality!\n\nSo, exactly what do we need to change?\n\n + allow a scalar or an an array identifier before a '[' token\n + allow an unadorned array identifier but mark it as an rvalue\n + add some more errors when we try to do bad things with arrays\n\nThat's about it. I've made these changes to the compiler. I hope that\nthey cover all the array issues, but it's likely that I've overlooked\nsomething else. If so, we'll revisit again.\n\n## Changes to `postfix()`\n\nIn the last part, I put in a \"band-aid\" fix to `postfix()` in `expr.c`,\nbut it's time to go back and fix it properly. We need to allow\nunadorned array identifiers but mark them as an rvalues. Here are the\nchanges:\n\n```c\nstatic struct ASTnode *postfix(void) {\n  ...\n  int rvalue=0;\n  ...\n  // An identifier, check that it exists. For arrays, set rvalue to 1.\n  if ((varptr = findsymbol(Text)) == NULL)\n    fatals(\"Unknown variable\", Text);\n  switch(varptr->stype) {\n    case S_VARIABLE: break;\n    case S_ARRAY: rvalue= 1; break;\n    default: fatals(\"Identifier not a scalar or array variable\", Text);\n  }\n\n  switch (Token.token) {\n    // Post-increment: skip over the token. Also same for post-decrement\n  case T_INC:\n    if (rvalue == 1)\n      fatals(\"Cannot ++ on rvalue\", Text);\n  ...\n    // Just a variable reference. Ensure any arrays\n    // cannot be treated as lvalues.\n  default:\n    if (varptr->stype == S_ARRAY) {\n      n = mkastleaf(A_ADDR, varptr->type, varptr, 0);\n      n->rvalue = rvalue;\n    } else\n      n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n```\n\nNow either scalar or array variables can be used unadorned, but arrays\ncan't be lvalues. Also, arrays can't be pre- or post-incremented.\nWe either load the address of the array base, or load the value in the\nscalar variable.\n\n## Changes to `array_access()`\n\nNow we need to modify `array_access()` in `expr.c` to allow pointers\nto be used with '[' ']' indexing. Here are the changes:\n\n```c\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array or a pointer.\n  if ((aryptr = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (aryptr->stype != S_ARRAY &&\n        (aryptr->stype == S_VARIABLE && !ptrtype(aryptr->type)))\n    fatals(\"Not an array or pointer\", Text);\n  \n  // Make a leaf node for it that points at the base of\n  // the array, or loads the pointer's value as an rvalue\n  if (aryptr->stype == S_ARRAY)\n    left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n  else {\n    left = mkastleaf(A_IDENT, aryptr->type, aryptr, 0);\n    left->rvalue= 1;\n  }\n  ...\n}\n```\n\nWe now check that the symbol exists and is either an array or a scalar\nvariable of pointer type. Once this is OK, we either load the address\nof the array base, or load the value in the pointer variable.\n\n## Testing the Code Changes\n\nI won't go through all the tests; instead I'll summarise them:\n\n + `tests/input124.c` checks that `ary++` can't be done on an array.\n + `tests/input125.c` checks that we can assign `ptr= ary` and then\n    access the array though the pointer.\n + `tests/input126.c` checks that we can't do `&ary`.\n + `tests/input127.c` calls a function with `fred(ary)` and ensures\n    that we can receive it as a pointer parameter.\n\n\n## Conclusion and What's Next\n\nWell, I was worried that I'd had to rewrite a whole pile of code to\nget arrays to work correctly. As it stood, the code was nearly right\nbut just needed some more tweaking to cover all the functionality that\nwe needed.\n\nIn the next part of our compiler writing journey, we will go back to\nmopping up. [Next step](../52_Pointers_pt2/Readme.md)\n"
  },
  {
    "path": "51_Arrays_pt2/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n  case P_CHAR:\n    return (1);\n  case P_INT:\n    return (4);\n  case P_LONG:\n    return (8);\n  default:\n    fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n  case P_CHAR:\n    return (offset);\n  case P_INT:\n  case P_LONG:\n    break;\n  default:\n    if (!ptrtype(type))\n      fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\" \"\\t.type\\t%s, @function\\n\", name, name);\n  fprintf(Outfile, \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\" \"\\tmovq\\t%%rsp, %%rbp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n\tfprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n      if (op == A_POSTINC)\n\tfprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n\tfprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Logically OR two registers and return a\n// register with the result, 1 or 0\nint cglogor(int r1, int r2) {\n  // Generate two labels\n  int Ltrue = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Test r2 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Didn't jump, so result is false\n  fprintf(Outfile, \"\\tmovq\\t$0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the true label, so result is true\n  cglabel(Ltrue);\n  fprintf(Outfile, \"\\tmovq\\t$1, %s\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n\n// Logically AND two registers and return a\n// register with the result, 1 or 0\nint cglogand(int r1, int r2) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Test r2 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Didn't jump, so result is true\n  fprintf(Outfile, \"\\tmovq\\t$1, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the false label, so result is false\n  cglabel(Lfalse);\n  fprintf(Outfile, \"\\tmovq\\t$0, %s\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->st_posn);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n      break;\n    case 8:\n      // Generate the pointer to a string literal. Treat a zero value\n      // as actually zero, not the label L0\n      if (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t  && initvalue != 0)\n\tfprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n      else\n\tfprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n      break;\n    default:\n      for (int i = 0; i < size; i++)\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Deal with pointers here as we can't put them in\n  // the switch statement\n  if (ptrtype(sym->type))\n    fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  else {\n    // Generate code depending on the function's type\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n      break;\n    case P_LONG:\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n      break;\n    default:\n      fatald(\"Bad function type in cgreturn:\", sym->type);\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 2:\n    fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 4:\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  default:\n    fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n    break;\n  case 2:\n  case 4:\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", name);\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Logically OR two registers and return a\n// register with the result, 1 or 0\nint cglogor(int r1, int r2) {\n  // Generate two labels\n  int Ltrue = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Test r2 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Didn't jump, so result is false\n  fprintf(Outfile, \"\\tmov\\t%s, 0\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the true label, so result is true\n  cglabel(Ltrue);\n  fprintf(Outfile, \"\\tmov\\t%s, 1\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n\n// Logically AND two registers and return a\n// register with the result, 1 or 0\nint cglogand(int r1, int r2) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Test r2 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Didn't jump, so result is true\n  fprintf(Outfile, \"\\tmov\\t%s, 1\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the false label, so result is false\n  cglabel(Lfalse);\n  fprintf(Outfile, \"\\tmov\\t%s, 0\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Deal with pointers here as we can't put them in\n  // the switch statement\n  if (ptrtype(sym->type))\n    fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  else {\n    // Generate code depending on the function's type\n    switch (sym->type) {\n      case P_CHAR:\n        fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n        break;\n      case P_INT:\n        fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n        break;\n      case P_LONG:\n        fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n        break;\n      default:\n        fatald(\"Bad function type in cgreturn:\", sym->type);\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_dumpsym;\t\t// If true, dump the symbol table\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "51_Arrays_pt2/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(void) {\n  int type, class=0;\n  struct symtable *ctype;\n\n  // Get the type inside the parentheses\n  type= parse_stars(parse_type(&ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return(type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree= optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type= tree->type;\n    tree= tree->left;\n  }\n\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return(tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue==0)\n      return(0);\n  }\n\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return(tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return(0);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym=NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree= NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym= addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym= addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym= addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym= addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist= (int *)malloc(sizeof(int));\n      sym->initlist[0]= parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, 0);\n      if (exprnode == NULL)\n        fatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode,\n\t\t\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t// New symbol table entry\n  int nelems= -1;\t// Assume the number of elements won't be given\n  int maxelems;\t\t// The maximum number of elements in the init list\n  int *initlist;\t// The list of initial elements \n  int i=0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems= parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class,\n\t\t  0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems= nelems;\n    else\n      maxelems= TABLE_INCREMENT;\n    initlist= (int *)malloc(maxelems *sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n        fatal(\"Too many values in initialisation list\");\n\n      initlist[i++]= parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n        maxelems += TABLE_INCREMENT;\n        initlist= (int *)realloc(initlist, maxelems *sizeof(int));\n      }\n\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n        scan(&Token);\n\tbreak;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j=i; j < sym->nelems; j++) initlist[j]=0;\n    if (i > nelems) nelems = i;\n    sym->initlist= initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  sym->nelems= nelems;\n  sym->size= sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n        paramcnt= 0; scan(&Token); break;\n      }\n    }\n\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree= optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t= declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t== -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead==NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name= NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class,\n\t\t\t\t\t   struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree= NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n        fatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree== NULL)\n      *gluetree= tree;\n    else\n      *gluetree = mkastnode(A_GLUE, P_NONE, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nint alloc_register(void);\nvoid freeall_registers(int keepreg);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cglogor(int r1, int r2);\nint cglogand(int r1, int r2);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\nvoid dumptable(struct symtable *head, char *name, int indent);\nvoid dumpsymtables(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(void);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "51_Arrays_pt2/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -w-ptr -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_QUESTION, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\n  A_TERNARY, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "51_Arrays_pt2/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree = mkastnode(A_GLUE, P_NONE, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree = mkastunary(A_FUNCCALL, funcptr->type, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(void) {\n  struct ASTnode *left, *right;\n  struct symtable *aryptr;\n\n  // Check that the identifier has been defined as an array or a pointer.\n  if ((aryptr = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (aryptr->stype != S_ARRAY &&\n\t(aryptr->stype == S_VARIABLE && !ptrtype(aryptr->type)))\n    fatals(\"Not an array or pointer\", Text);\n  \n  // Make a leaf node for it that points at the base of\n  // the array, or loads the pointer's value as an rvalue\n  if (aryptr->stype == S_ARRAY)\n    left = mkastleaf(A_ADDR, aryptr->type, aryptr, 0);\n  else {\n    left = mkastleaf(A_IDENT, aryptr->type, aryptr, 0);\n    left->rvalue= 1;\n  }\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, A_ADD);\n\n  // Return an AST tree where the array's base has the offset\n  // added to it, and dereference the element. Still an lvalue\n  // at this point.\n  left = mkastnode(A_ADD, aryptr->type, left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, value_at(left->type), left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(int withpointer) {\n  struct ASTnode *left, *right;\n  struct symtable *compvar;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the identifier has been declared as a\n  // struct/union or a struct/union pointer\n  if ((compvar = findsymbol(Text)) == NULL)\n    fatals(\"Undeclared variable\", Text);\n  if (withpointer && compvar->type != pointer_to(P_STRUCT)\n      && compvar->type != pointer_to(P_UNION))\n    fatals(\"Undeclared variable\", Text);\n  if (!withpointer && compvar->type != P_STRUCT && compvar->type != P_UNION)\n    fatals(\"Undeclared variable\", Text);\n\n  // If a pointer to a struct/union, get the pointer's value.\n  // Otherwise, make a leaf node that points at the base\n  // Either way, it's an rvalue\n  if (withpointer) {\n    left = mkastleaf(A_IDENT, pointer_to(compvar->type), compvar, 0);\n  } else\n    left = mkastleaf(A_ADDR, compvar->type, compvar, 0);\n  left->rvalue = 1;\n\n  // Get the details of the composite type\n  typeptr = compvar->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);\n  left = mkastunary(A_DEREF, m->type, left, NULL, 0);\n  return (left);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  struct symtable *enumptr;\n  int rvalue=0;\n\n  // If the identifier matches an enum value,\n  // return an A_INTLIT node\n  if ((enumptr = findenumval(Text)) != NULL) {\n    scan(&Token);\n    return (mkastleaf(A_INTLIT, P_INT, NULL, enumptr->st_posn));\n  }\n  // Scan in the next token to see if we have a postfix expression\n  scan(&Token);\n\n  // Function call\n  if (Token.token == T_LPAREN)\n    return (funccall());\n\n  // An array reference\n  if (Token.token == T_LBRACKET)\n    return (array_access());\n\n  // Access into a struct or union\n  if (Token.token == T_DOT)\n    return (member_access(0));\n  if (Token.token == T_ARROW)\n    return (member_access(1));\n\n  // An identifier, check that it exists. For arrays, set rvalue to 1.\n  if ((varptr = findsymbol(Text)) == NULL)\n    fatals(\"Unknown variable\", Text);\n  switch(varptr->stype) {\n    case S_VARIABLE: break;\n    case S_ARRAY: rvalue= 1; break;\n    default: fatals(\"Identifier not a scalar or array variable\", Text);\n  }\n\n  switch (Token.token) {\n    // Post-increment: skip over the token\n  case T_INC:\n    if (rvalue == 1)\n      fatals(\"Cannot ++ on rvalue\", Text);\n    scan(&Token);\n    n = mkastleaf(A_POSTINC, varptr->type, varptr, 0);\n    break;\n\n    // Post-decrement: skip over the token\n  case T_DEC:\n    if (rvalue == 1)\n      fatals(\"Cannot -- on rvalue\", Text);\n    scan(&Token);\n    n = mkastleaf(A_POSTDEC, varptr->type, varptr, 0);\n    break;\n\n    // Just a variable reference. Ensure any arrays\n    // cannot be treated as lvalues.\n  default:\n    if (varptr->stype == S_ARRAY) {\n      n = mkastleaf(A_ADDR, varptr->type, varptr, 0);\n      n->rvalue = rvalue;\n    } else\n      n = mkastleaf(A_IDENT, varptr->type, varptr, 0);\n  }\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  int id;\n  int type = 0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type = parse_stars(parse_type(&ctype, &class));\n    // Get the type's size\n    size = typesize(type, ctype);\n    rparen();\n    // Return a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, id);\n    break;\n\n  case T_IDENT:\n    return (postfix());\n\n  case T_LPAREN:\n    // Beginning of a parenthesised expression, skip the '('.\n    scan(&Token);\n\n\n    // If the token after is a type identifier, this is a cast expression\n    switch (Token.token) {\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      if (findtypedef(Text) == NULL) {\n\tn = binexpr(0);\n\tbreak;\n      }\n    case T_VOID:\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n      // Get the type inside the parentheses\n      type = parse_cast();\n      // Skip the closing ')' and then parse the following expression\n      rparen();\n\n    default:\n      n = binexpr(0);\t\t// Scan in the expression\n    }\n\n    // We now have at least an expression in n, and possibly a non-zero type in type\n    // if there was a cast. Skip the closing ')' if there was no cast.\n    if (type == 0)\n      rparen();\n    else\n      // Otherwise, make a unary AST node for the cast\n      n = mkastunary(A_CAST, type, n, NULL, 0);\n    return (n);\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatald(\"Syntax error, token\", tokentype);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatald(\"Token with no precedence in op_precedence:\", tokentype);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatald(\"Syntax error, token\", tokentype);\n  return (prec);\n}\n\n// prefix_expression: primary\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Prevent '&' being performed on an array\n    if (tree->sym->stype == S_ARRAY)\n      fatal(\"& operator cannot be performed on an array\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree = mkastunary(A_DEREF, value_at(tree->type), tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this to int so that it's signed\n    tree->rvalue = 1;\n    tree = modify_type(tree, P_INT, 0);\n    tree = mkastunary(A_NEGATE, tree->type, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree, NULL, 0);\n    break;\n  default:\n    tree = primary();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp= binexpr(0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. XXX We should also\n      // consider the third expression's type.\n      return (mkastnode(A_TERNARY, right->type, left, right, ltemp, NULL, 0));\n\n    case A_ASSIGN:\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n      break;\n\n    default:\n      // We are not doing a ternary or assignment, so both trees should\n      // be rvalues. Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, ASTop);\n      rtemp = modify_type(right, left->type, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left, NULL, right, NULL, 0);\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs(reg);\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    if (c->left) genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs(NOREG);\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    genfreeregs(NOREG);\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n  case A_IF:\n    return (genIF(n, looptoplabel, loopendlabel));\n  case A_WHILE:\n    return (genWHILE(n));\n  case A_SWITCH:\n    return (genSWITCH(n));\n  case A_FUNCCALL:\n    return (gen_funccall(n));\n  case A_TERNARY:\n    return (gen_ternary(n));\n  case A_GLUE:\n    // Do each child statement, and free the\n    // registers after each child\n    if (n->left != NULL)\n      genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    if (n->right != NULL)\n      genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    return (NOREG);\n  case A_FUNCTION:\n    // Generate the function's preamble before the code\n    // in the child sub-tree\n    cgfuncpreamble(n->sym);\n    genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n    cgfuncpostamble(n->sym);\n    return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n  case A_ADD:\n    return (cgadd(leftreg, rightreg));\n  case A_SUBTRACT:\n    return (cgsub(leftreg, rightreg));\n  case A_MULTIPLY:\n    return (cgmul(leftreg, rightreg));\n  case A_DIVIDE:\n    return (cgdiv(leftreg, rightreg));\n  case A_AND:\n    return (cgand(leftreg, rightreg));\n  case A_OR:\n    return (cgor(leftreg, rightreg));\n  case A_XOR:\n    return (cgxor(leftreg, rightreg));\n  case A_LSHIFT:\n    return (cgshl(leftreg, rightreg));\n  case A_RSHIFT:\n    return (cgshr(leftreg, rightreg));\n  case A_EQ:\n  case A_NE:\n  case A_LT:\n  case A_GT:\n  case A_LE:\n  case A_GE:\n    // If the parent AST node is an A_IF, A_WHILE or A_TERNARY,\n    // generate a compare followed by a jump. Otherwise, compare\n    // registers and set one to 1 or 0 based on the comparison.\n    if (parentASTop == A_IF || parentASTop == A_WHILE ||\n\tparentASTop == A_TERNARY)\n      return (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n    else\n      return (cgcompare_and_set(n->op, leftreg, rightreg));\n  case A_INTLIT:\n    return (cgloadint(n->a_intvalue, n->type));\n  case A_STRLIT:\n    return (cgloadglobstr(n->a_intvalue));\n  case A_IDENT:\n    // Load our value if we are an rvalue\n    // or we are being dereferenced\n    if (n->rvalue || parentASTop == A_DEREF) {\n      if (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC) {\n\treturn (cgloadglob(n->sym, n->op));\n      } else {\n\treturn (cgloadlocal(n->sym, n->op));\n      }\n    } else\n      return (NOREG);\n  case A_ASPLUS:\n  case A_ASMINUS:\n  case A_ASSTAR:\n  case A_ASSLASH:\n  case A_ASSIGN:\n\n    // For the '+=' and friends operators, generate suitable code\n    // and get the register with the result. Then take the left child,\n    // make it the right child so that we can fall into the assignment code.\n    switch (n->op) {\n    case A_ASPLUS:\n      leftreg = cgadd(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASMINUS:\n      leftreg = cgsub(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASSTAR:\n      leftreg = cgmul(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASSLASH:\n      leftreg = cgdiv(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    }\n\n    // Now into the assignment code\n    // Are we assigning to an identifier or through a pointer?\n    switch (n->right->op) {\n    case A_IDENT:\n      if (n->right->sym->class == C_GLOBAL ||\n\t  n->right->sym->class == C_STATIC)\n\treturn (cgstorglob(leftreg, n->right->sym));\n      else\n\treturn (cgstorlocal(leftreg, n->right->sym));\n    case A_DEREF:\n      return (cgstorderef(leftreg, rightreg, n->right->type));\n    default:\n      fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n    }\n  case A_WIDEN:\n    // Widen the child's type to the parent's type\n    return (cgwiden(leftreg, n->left->type, n->type));\n  case A_RETURN:\n    cgreturn(leftreg, Functionid);\n    return (NOREG);\n  case A_ADDR:\n    return (cgaddress(n->sym));\n  case A_DEREF:\n    // If we are an rvalue, dereference to get the value we point at,\n    // otherwise leave it for A_ASSIGN to store through the pointer\n    if (n->rvalue)\n      return (cgderef(leftreg, n->left->type));\n    else\n      return (leftreg);\n  case A_SCALE:\n    // Small optimisation: use shift if the\n    // scale value is a known power of two\n    switch (n->a_size) {\n    case 2:\n      return (cgshlconst(leftreg, 1));\n    case 4:\n      return (cgshlconst(leftreg, 2));\n    case 8:\n      return (cgshlconst(leftreg, 3));\n    default:\n      // Load a register with the size and\n      // multiply the leftreg by this size\n      rightreg = cgloadint(n->a_size, P_INT);\n      return (cgmul(leftreg, rightreg));\n    }\n  case A_POSTINC:\n  case A_POSTDEC:\n    // Load and decrement the variable's value into a register\n    // and post increment/decrement it\n    if (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC)\n      return (cgloadglob(n->sym, n->op));\n    else\n      return (cgloadlocal(n->sym, n->op));\n  case A_PREINC:\n  case A_PREDEC:\n    // Load and decrement the variable's value into a register\n    // and pre increment/decrement it\n    if (n->left->sym->class == C_GLOBAL || n->left->sym->class == C_STATIC)\n      return (cgloadglob(n->left->sym, n->op));\n    else\n      return (cgloadlocal(n->left->sym, n->op));\n  case A_NEGATE:\n    return (cgnegate(leftreg));\n  case A_INVERT:\n    return (cginvert(leftreg));\n  case A_LOGNOT:\n    return (cglognot(leftreg));\n  case A_LOGOR:\n    return (cglogor(leftreg, rightreg));\n  case A_LOGAND:\n    return (cglogand(leftreg, rightreg));\n  case A_TOBOOL:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, set the register\n    // to 0 or 1 based on it's zeroeness or non-zeroeness\n    return (cgboolean(leftreg, parentASTop, iflabel));\n  case A_BREAK:\n    cgjump(loopendlabel);\n    return (NOREG);\n  case A_CONTINUE:\n    cgjump(looptoplabel);\n    return (NOREG);\n  case A_CAST:\n    return (leftreg);\t\t// Not much to do\n  default:\n    fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs(int keepreg) {\n  freeall_registers(keepreg);\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "51_Arrays_pt2/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "51_Arrays_pt2/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "51_Arrays_pt2/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "51_Arrays_pt2/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "51_Arrays_pt2/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "51_Arrays_pt2/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "51_Arrays_pt2/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "51_Arrays_pt2/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "51_Arrays_pt2/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix; posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token= 0;\t\t// and set there is no lookahead token\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n\n  // Dump the symbol table if requested\n  if (O_dumpsym) {\n    printf(\"Symbols for %s\\n\", filename);\n    dumpsymtables();\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcSTM] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -M dump the symbol table for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_dumpsym = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'M':\n\t  O_dumpsym = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  char *p;\n\n  p = strchr(s, c);\n  return (p ? p - s : -1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (c == '#') {\t\t// We've hit a pre-processor statement\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n  }\n\n  if ('\\n' == c)\n    Line++;\t\t\t// Increment line count\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return n;\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn hexchar();\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST = mkastunary(A_TOBOOL, condAST->type, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, 0, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, 0, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *body, *n, *c;\n  struct ASTnode *casetree= NULL, *casetail;\n  int inloop=1, casecount=0;\n  int seendefault=0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left= binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n= mkastunary(A_SWITCH, 0, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch(Token.token) {\n      // Leave the loop when we hit a '}'\n      case T_RBRACE: if (casecount==0)\n\t\t\tfatal(\"No cases in switch\");\n\t\t     inloop=0; break;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token==T_DEFAULT) {\n\t  ASTop= A_DEFAULT; seendefault= 1; scan(&Token);\n\t} else  {\n\t  ASTop= A_CASE; scan(&Token);\n\t  left= binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue= left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n  \t  // that there isn't a duplicate case value\n\t  for (c= casetree; c != NULL; c= c -> right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n        }\n\n\t// Scan the ':' and increment the casecount\n\tmatch(T_COLON, \":\");\n\tcasecount++;\n\n\t// If the next token is a T_CASE, the existing case will fall\n\t// into the next case. Otherwise, parse the case body.\n\tif (Token.token == T_CASE) \n\t  body= NULL;\n\telse\n\t  body= compound_statement(1);\n\n\t// Build a sub-tree with any compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree==NULL) {\n\t  casetree= casetail= mkastunary(ASTop, 0, body, NULL, casevalue);\n\t} else {\n\t  casetail->right= mkastunary(ASTop, 0, body, NULL, casevalue);\n\t  casetail= casetail->right;\n\t}\n\tbreak;\n      default:\n        fatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue= casecount;\n  n->right= casetree;\n  rbrace();\n\n  return(n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return(stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt= binexpr(0); semi(); return(stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt= binexpr(0); semi(); return(stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, left, NULL, tree, NULL, 0);\n    }\n\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE) return(left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT)) return(left);\n  }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list,\n\t\t\t\t      int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class == 0 || class == list->class)\n\treturn (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead = Globtail = NULL;\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Membhead = Membtail = NULL;\n  Structhead = Structtail = NULL;\n  Unionhead = Uniontail = NULL;\n  Enumhead = Enumtail = NULL;\n  Typehead = Typetail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev = NULL;\n\n  // Walk the global table looking for static entries\n  for (g = Globhead; g != NULL; g = g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL)\n\tprev->next = g->next;\n      else\n\tGlobhead->next = g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n\tif (prev != NULL)\n\t  Globtail = prev;\n\telse\n\t  Globtail = Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev = g;\n}\n\n// Dump a single symbol\nstatic void dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n  case P_VOID:\n    printf(\"void \");\n    break;\n  case P_CHAR:\n    printf(\"char \");\n    break;\n  case P_INT:\n    printf(\"int \");\n    break;\n  case P_LONG:\n    printf(\"long \");\n    break;\n  case P_STRUCT:\n    if (sym->ctype != NULL)\n      printf(\"struct %s \", sym->ctype->name);\n    else\n      printf(\"struct %s \", sym->name);\n    break;\n  case P_UNION:\n    if (sym->ctype != NULL)\n      printf(\"union %s \", sym->ctype->name);\n    else\n      printf(\"union %s \", sym->name);\n    break;\n  default:\n    printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++)\n    printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n  case S_VARIABLE:\n    break;\n  case S_FUNCTION:\n    printf(\"()\");\n    break;\n  case S_ARRAY:\n    printf(\"[]\");\n    break;\n  default:\n    printf(\" unknown stype\");\n  }\n\n  switch (sym->class) {\n  case C_GLOBAL:\n    printf(\": global\");\n    break;\n  case C_LOCAL:\n    printf(\": local\");\n    break;\n  case C_PARAM:\n    printf(\": param\");\n    break;\n  case C_EXTERN:\n    printf(\": extern\");\n    break;\n  case C_STATIC:\n    printf(\": static\");\n    break;\n  case C_STRUCT:\n    printf(\": struct\");\n    break;\n  case C_UNION:\n    printf(\": union\");\n    break;\n  case C_MEMBER:\n    printf(\": member\");\n    break;\n  case C_ENUMTYPE:\n    printf(\": enumtype\");\n    break;\n  case C_ENUMVAL:\n    printf(\": enumval\");\n    break;\n  case C_TYPEDEF:\n    printf(\": typedef\");\n    break;\n  default:\n    printf(\": unknown class\");\n  }\n\n  switch (sym->stype) {\n  case S_VARIABLE:\n    if (sym->class == C_ENUMVAL)\n      printf(\", value %d\\n\", sym->st_posn);\n    else\n      printf(\", size %d\\n\", sym->size);\n    break;\n  case S_FUNCTION:\n    printf(\", %d params\\n\", sym->nelems);\n    break;\n  case S_ARRAY:\n    printf(\", %d elems, size %d\\n\", sym->nelems, sym->size);\n    break;\n  }\n\n  switch (sym->type & (~0xf)) {\n  case P_STRUCT:\n  case P_UNION:\n    dumptable(sym->member, NULL, 4);\n  }\n\n  switch (sym->stype) {\n  case S_FUNCTION:\n    dumptable(sym->member, NULL, 4);\n  }\n}\n\n// Dump one symbol table\nvoid dumptable(struct symtable *head, char *name, int indent) {\n  struct symtable *sym;\n\n  if (head != NULL && name != NULL)\n    printf(\"%s\\n--------\\n\", name);\n  for (sym = head; sym != NULL; sym = sym->next)\n    dumpsym(sym, indent);\n}\n\nvoid dumpsymtables(void) {\n  dumptable(Globhead, \"Global\", 0);\n  printf(\"\\n\");\n  dumptable(Enumhead, \"Enums\", 0);\n  printf(\"\\n\");\n  dumptable(Typehead, \"Typedefs\", 0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input032.c",
    "content": "Unknown variable:cow on line 4 of input032.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input042.c",
    "content": "Undeclared function:fred on line 3 of input042.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input043.c",
    "content": "Undeclared variable:b on line 3 of input043.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input044.c",
    "content": "Unknown variable:z on line 3 of input044.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input059.c",
    "content": "Undeclared variable:y on line 3 of input059.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input060.c",
    "content": "Undeclared variable:x on line 3 of input060.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input061.c",
    "content": "Undeclared variable:x on line 3 of input061.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input093.c",
    "content": "Unknown variable:fred on line 1 of input093.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input124.c",
    "content": "Cannot ++ on rvalue:ary on line 6 of input124.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/err.input126.c",
    "content": "Unknown variable:ptr on line 7 of input126.c\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input122.c",
    "content": "#include <stdio.h>\n\nint x, y, z1, z2;\n\nint main() {\n  for (x= 0; x <= 1; x++) {\n    for (y= 0; y <= 1; y++) {\n      z1= x || y; z2= x && y;\n      printf(\"x %d, y %d, x || y %d, x && y %d\\n\", x, y, z1, z2);\n    }\n  }\n  \n  //z= x || y;\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input123.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  for (x=0; x < 20; x++)\n    switch(x) {\n      case 2:\n      case 3:\n      case 5:\n      case 7:\n      case 11: printf(\"%2d infant prime\\n\", x); break;\n      case 13:\n      case 17:\n      case 19: printf(\"%2d teen   prime\\n\", x); break;\n      case 0:\n      case 1:\n      case 4:\n      case 6:\n      case 8:\n      case 9:\n      case 10:\n      case 12: printf(\"%2d infant composite\\n\", x); break;\n      default: printf(\"%2d teen   composite\\n\", x); break;\n    }\n\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input124.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary++;\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input125.c",
    "content": "#include <stdio.h>\n\nint ary[5];\nint *ptr;\nint x;\n\nint main() {\n  ary[3]= 2008;\n  ptr= ary;\t\t\t// Load ary's address into ptr\n  x= ary[3]; printf(\"%d\\n\", x);\n  x= ptr[3]; printf(\"%d\\n\", x); // Treat ptr as an array\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input126.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary[3]= 2008;\n  ptr= &ary;\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/input127.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nvoid fred(int *ptr) {\t\t// Receive a pointer\n  printf(\"%d\\n\", ptr[3]);\n}\n\nint main() {\n  ary[3]= 2008;\n  printf(\"%d\\n\", ary[3]);\n  fred(ary);\t\t\t// Pass ary as a pointer\n  return(0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "51_Arrays_pt2/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input122.c",
    "content": "x 0, y 0, x || y 0, x && y 0\nx 0, y 1, x || y 1, x && y 0\nx 1, y 0, x || y 1, x && y 0\nx 1, y 1, x || y 1, x && y 1\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input123.c",
    "content": " 0 infant composite\n 1 infant composite\n 2 infant prime\n 3 infant prime\n 4 infant composite\n 5 infant prime\n 6 infant composite\n 7 infant prime\n 8 infant composite\n 9 infant composite\n10 infant composite\n11 infant prime\n12 infant composite\n13 teen   prime\n14 teen   composite\n15 teen   composite\n16 teen   composite\n17 teen   prime\n18 teen   composite\n19 teen   prime\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input125.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "51_Arrays_pt2/tests/out.input127.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "51_Arrays_pt2/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "51_Arrays_pt2/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "51_Arrays_pt2/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type, struct ASTnode *left,\n\t\t\t    struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "51_Arrays_pt2/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));\n  }\n\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return(tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "52_Pointers_pt2/Readme.md",
    "content": "# Part 52: Pointers, part 2\n\nIn this part of our compiler writing journey, I started with a pointer\nissue that needed to fix, and I ended up restructuring about half of\n`expr.c` and changing the API to another quarter of the functions in the\ncompiler. So this is a big step in terms of number of lines touched, but\nnot a big step in terms of fixes or improvements.\n\n## The Problem\n\nWe'll start with the problem that caused all of this. When running the\ncompiler's source code through itself, I realised that I couldn't parse\na chain of pointers, e.g. something like the expression:\n\n```c\n  ptr->next->next->next\n```\n\nThe reason for this is that `primary()` is called and gets the value of\nthe identifier at the beginning of the expression. If it sees a following\npostfix operator, it then calls `postfix()` to deal with it. `postfix()`\ndeals with, for example, one `->` operator and returns. And that's it.\nThere is no loop to follow a chain of `->` operators.\n\nEven worse, `primary()` looks for a single identifier. This means that\nit won't parse the following, either:\n\n```c\n  ptrarray[4]->next     OR\n  unionvar.member->next\n```\n\nbecause neither of these are single identifers before the `->` operator.\n\n## How Did This Happen?\n\nThis happened because of the rapid prototyping nature of our development.\nI only add functionality one small step at a time, and I don't usually\nlook too far ahead in terms of future needs. So, now and then, we have to\nundo what has been written to make it more general and flexible.\n\n## How to Fix It?\n\nIf we look at the\n[BNF Grammar for C](https://www.lysator.liu.se/c/ANSI-C-grammar-y.html), we\nsee this:\n\n```\nprimary_expression\n        : IDENTIFIER\n        | CONSTANT\n        | STRING_LITERAL\n        | '(' expression ')'\n        ;\n\npostfix_expression\n        : primary_expression\n        | postfix_expression '[' expression ']'\n        | postfix_expression '(' ')'\n        | postfix_expression '(' argument_expression_list ')'\n        | postfix_expression '.' IDENTIFIER\n        | postfix_expression '->' IDENTIFIER\n        | postfix_expression '++'\n        | postfix_expression '--'\n        ;\n```\n\nIn other words, we have things backwards. `postfix` should call `primary()`\nto get an AST node that represents the identifier. Then, we can loop looking\nfor any postfix tokens, parse them and add new AST parent nodes on to the\nidentifier node that we received back from `primary()`.\n\nIt all sounds nice and simple except for one thing. The current\n`primary()` doesn't build an AST node; it only parses the identifier and\nleaves it in `Text`. It's the job of `postfix()` to build the AST node or\nAST tree for the identifier plus any postfix operations.\n\nAt the same time, the AST node structure in `defs.h` only knows about the\nprimitive type:\n\n```c\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;           // \"Operation\" to be performed on this tree\n  int type;         // Type of any expression this tree generates\n  int rvalue;       // NOTE: no ctype\n  ...\n};\n```\n\nThe reason for this is that we only recently added structs and unions. This,\nand the fact that `postfix()` did most of the parsing work meant that we\nhaven't needed to store a pointer to the struct or union symbol for\nan identifier which is a struct or union.\n\nSo, to fix things, we need to:\n\n  1. Add in a `ctype` pointer to `struct ASTnode` so that the full type\n     is stored in each AST node.\n  2. Find and fix all the functions that build AST nodes, and all the calls\n     to these function, so that the `ctype` of a node is stored.\n  3. Move `primary()` up near the top of `expr.c` and get it to build\n     an AST node.\n  4. Get `postfix()` to call `primary()` to get the unadorned AST node\n     for an identifier (A_IDENT).\n  5. Get `postfix()` to loop while there are postfix operators to process.\n\nThat's a lot and, as the AST node calls are sprinkled everywhere, every\nsingle source file in the compiler will need to be touched. Sigh.\n     \n## Changes to the AST Node Functions\n\nI'm not going to bore you with all the details, but we can start with\nthe change to the AST node structure in `defs.h`, and the main function\nin `tree.c` that builds an AST node:\n\n```c\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  ...\n};\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n                          struct symtable *ctype, ...) {\n  ...\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->ctype = ctype;\n  ...\n}\n```\n\nThere are also changes to `mkastleaf()` and `mkastunary()`: they now receive\na `ctype` and call `mkastnode()` with this argument.\n\nIn the compiler there are about 40 calls to these three functions, so I'm not\ngoing to go through each and every one. For most of them, there is a primitive\n`type` and ` ctype` pointer available. Some calls set the AST node\ntype to P_INT and thus the `ctype` is NULL. Some calls set the AST node type\nto P_NONE and, again, the `ctype` is NULL.\n\n\n## Changes to `modify_type()`\n\nThe `modify_type()` is used to determine if an AST node's type is compatible\nwith another type and, if necessary, to widen the node to match the other\ntype. It calls `mkastunary()` and thus we also need to provide it with a\n`ctype` argument. I've done this and, as a consequence, the six calls to\n`modify_type()` have had to be modified to pass in the `ctype` of the\ntype which we are comparing the AST node against.\n\n## Changes to `expr.c`\n\nNow we get to the meat of the changes, the restucturing of `primary()`\nand `postfix()`. I've already outlined what we have to do above. As with\nmuch of what we've done, there are a few wrinkles along the way to iron out.\n\n## Changes to `postfix()`\n\n`postfix()` actually looks much cleaner now:\n\n```c\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n\n  // Get the primary expression\n  n = primary();\n\n  // Loop until there are no more postfix operators\n  while (1) {\n    switch (Token.token) {\n    ...\n    default:\n      return (n);\n    }\n  }\n```\n\nWe now call `primary()` to get an identifier or a constant. Then we\nloop applying any postfix operators to the AST node we received from\n`primary()`. We call out to helper functions like `array_access()` and\n`member_access()` for `[..]`, `.` and `->` operators.\n\nWe do post-increment and post-decrement here. Now that there is a loop,\nwe have to check that we don't try to do these operations more than once.\nWe also check that the AST we received from `primary()` is an lvalue and\nnot an rvalue, as we need an address in memory to increment or decrement.\n\n## A New Function, `paren_expression()`\n\nI realised that the new `primary()` function was getting a bit too big, so\nI split some of its code off into a new function, `paren_expression()`. This\nparses expressions that are enclosed in `(..)`: casts and ordinary\nparenthesised expressions. The code is nearly identical to the old code, so\nI won't go into it here. It returns an AST node with the tree that represents\neither a cast expression or a parenthesised expression.\n\n## Changes to `primary()`\n\nThis is where the biggest change has occurred. Firstly, here are the tokens\nit looks for:\n\n + 'static', 'extern' which it complains about, because we can only be\n    parsing expressions in a local context.\n + 'sizeof()'\n + integer and string literals\n + identifiers: these could be known types (e.g. 'int'), names of enums,\n    names of typedefs, function names, array names and/or scalar variable\n    names. This section is the biggest part of `primary()` and, on reflection,\n    perhaps I should make this into its own function.\n + `(..)` which is where  `paren_expression()` gets called.\n\nLooking at the code, `primary()` now builds AST nodes for each of the above to\nreturn to `postfix()`. This used to be done in `postfix` but I now do it\nin `primary()`.\n\n## Changes to `member_access()`\n\nWith the previous `member_access()`, the global `Text` variable still\nheld the identifier, and `member_access()` built the AST node to represent\nthe struct/union identifier.\n\nIn the current `member_access()`, we receive the AST node for the\nstruct/union identifier, and this could be an array element or a member of\nanother struct/union.\n\nSo the code is different in that we don't build the leaf AST node for the\noriginal identifier anymore. We still build AST nodes to add on the offset\nfrom the base and dereference the pointer to the member.\n\nOne other difference is this code:\n\n```c\n  // Check that the left AST tree is a struct or union.\n  // If so, change it from an A_IDENT to an A_ADDR so that\n  // we get the base address, not the value at this address.\n  if (!withpointer) {\n    if (left->type == P_STRUCT || left->type == P_UNION)\n      left->op = A_ADDR;\n    else\n      fatal(\"Expression is not a struct/union\");\n  }\n```\n\nConsider the expression `foo.bar`. `foo` is the name of a struct, for example,\nand `bar` is a member of that struct`.\n\nIn `primary()` we will have created an A_IDENT AST node for `foo`, because\nwe can't tell if this is a scalar variable (e.g. `int foo`) or a structure\n(e.g. `struct fred foo`). Now that we know it's a struct or a union, we\nneed the base address of the struct and not the value at the base address.\nSo, the code converts the A_IDENT AST node operation into an A_ADDR operation\non the identifier.\n\n## Testing the Code\n\nI think I spent about two hours running through our hundred plus regression\ntests, finding things I'd missed and fixing them up. It certainly felt good\nto get through all the tests again.\n\n`tests/input128.c` now checks that we can follow a chain of pointers, which\nwas the whole point of this exercise:\n\n```c\nstruct foo {\n  int val;\n  struct foo *next;\n};\n\nstruct foo head, mid, tail;\n\nint main() {\n  struct foo *ptr;\n  tail.val= 20; tail.next= NULL;\n  mid.val= 15; mid.next= &tail;\n  head.val= 10; head.next= &mid;\n\n  ptr= &head;\n  printf(\"%d %d\\n\", head.val, ptr->val);\n  printf(\"%d %d\\n\", mid.val, ptr->next->val);\n  printf(\"%d %d\\n\", tail.val, ptr->next->next->val);\n  return(0);\n}\n```\n\nAnd `tests/input129.c` checks that we can't post-increment twice in a row.\n\n## One Other Change: `Linestart`\n\nThere is one more change that I made to the compiler as part of our\neffort to get it to self-compile.\n\nThe scanner was looking for a '#' token. When it saw this token, it assumed\nthat we had hit a C pre-processor line and it parsed this line. Unfortunately,\nI hadn't tied the scanner down to looking in the first column of each line.\nSo, when our compiler hit this source code line:\n\n```c\n  while (c == '#') {\n```\n\nit got upset that the ')' '{' were not a C pre-processor line.\n\nWe now have a `Linestart` variable which flags if the scanner is at the\nfirst column of a new line or not. The main function which is modified\nis `next()` in `scan.c`. I think the changes are a bit ugly but they work;\nI should come back sometime and see if I can clean this up a bit. Anyway,\nwe only expect C pre-processor lines when we see a '#' in column 1.\n\n\n## Conclusion and What's Next\n\nIn the next part of our compiler writing journey, I'll go back to feeding\nthe compiler source code to itself, see what errors pop and up choose one\nor more to fix. [Next step](../53_Mop_up_pt2/Readme.md)\n"
  },
  {
    "path": "52_Pointers_pt2/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n\tfatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\" \"\\t.type\\t%s, @function\\n\", name, name);\n  fprintf(Outfile, \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\" \"\\tmovq\\t%%rsp, %%rbp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn,\n\t\treglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn,\n\t\treglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Logically OR two registers and return a\n// register with the result, 1 or 0\nint cglogor(int r1, int r2) {\n  // Generate two labels\n  int Ltrue = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Test r2 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Didn't jump, so result is false\n  fprintf(Outfile, \"\\tmovq\\t$0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the true label, so result is true\n  cglabel(Ltrue);\n  fprintf(Outfile, \"\\tmovq\\t$1, %s\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return (r1);\n}\n\n// Logically AND two registers and return a\n// register with the result, 1 or 0\nint cglogand(int r1, int r2) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Test r2 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Didn't jump, so result is true\n  fprintf(Outfile, \"\\tmovq\\t$1, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the false label, so result is false\n  cglabel(Lfalse);\n  fprintf(Outfile, \"\\tmovq\\t$0, %s\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return (r1);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r],\n\t\tsym->st_posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r],\n\t\tsym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n      case 1:\n\tfprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n\tbreak;\n      case 8:\n\t// Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n\tif (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t    && initvalue != 0)\n\t  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n\telse\n\t  fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n\tbreak;\n      default:\n\tfor (int i = 0; i < size; i++)\n\t  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Deal with pointers here as we can't put them in\n  // the switch statement\n  if (ptrtype(sym->type))\n    fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  else {\n    // Generate code depending on the function's type\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n\tbreak;\n      case P_LONG:\n\tfprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n\tbreak;\n      default:\n\tfatald(\"Bad function type in cgreturn:\", sym->type);\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", name);\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Logically OR two registers and return a\n// register with the result, 1 or 0\nint cglogor(int r1, int r2) {\n  // Generate two labels\n  int Ltrue = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Test r2 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Didn't jump, so result is false\n  fprintf(Outfile, \"\\tmov\\t%s, 0\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the true label, so result is true\n  cglabel(Ltrue);\n  fprintf(Outfile, \"\\tmov\\t%s, 1\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n\n// Logically AND two registers and return a\n// register with the result, 1 or 0\nint cglogand(int r1, int r2) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Test r2 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Didn't jump, so result is true\n  fprintf(Outfile, \"\\tmov\\t%s, 1\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the false label, so result is false\n  cglabel(Lfalse);\n  fprintf(Outfile, \"\\tmov\\t%s, 0\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (int i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n\n  /* put string in readable format on a single line\n  // probably went overboard with error checking\n  int comma = 0, quote = 0, start = 1;\n  fprintf(Outfile, \"\\tdb\\t\");\n  for (cptr=strvalue; *cptr; cptr++) {\n    if ( ! isprint(*cptr) )\n      if (comma || start) {\n        fprintf(Outfile, \"%d, \", *cptr);\n        start = 0;\n        comma = 1;\n      }\n      else if (quote) {\n        fprintf(Outfile, \"\\', %d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n      else {\n        fprintf(Outfile, \"%d, \", *cptr);\n        comma = 1;\n        quote = 0;\n      }\n    else\n      if (start || comma) {\n        fprintf(Outfile, \"\\'%c\", *cptr);\n        start = comma = 0;\n        quote = 1;\n      }\n      else {\n        fprintf(Outfile, \"%c\", *cptr);\n        comma = 0;\n        quote = 1;\n      }\n  }\n  if (comma || start)\n    fprintf(Outfile, \"0\\n\");\n  else\n    fprintf(Outfile, \"\\', 0\\n\");\n  */\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Deal with pointers here as we can't put them in\n  // the switch statement\n  if (ptrtype(sym->type))\n    fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  else {\n    // Generate code depending on the function's type\n    switch (sym->type) {\n      case P_CHAR:\n        fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n        break;\n      case P_INT:\n        fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n        break;\n      case P_LONG:\n        fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n        break;\n      default:\n        fatald(\"Bad function type in cgreturn:\", sym->type);\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Linestart;\t\t     \t// True if at start of a line\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\nextern char *Tstring[];\t\t\t// List of token strings\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_dumpsym;\t\t// If true, dump the symbol table\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "52_Pointers_pt2/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Get the type inside the parentheses\n  type = parse_stars(parse_type(ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return (type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree = optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type = tree->type;\n    tree = tree->left;\n  }\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return (tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue == 0)\n      return (0);\n  }\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return (tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree = NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym = addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym = addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist = (int *) malloc(sizeof(int));\n      sym->initlist[0] = parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym->ctype, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, varnode->ctype, 0);\n      if (exprnode == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode->ctype, exprnode,\n\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t\t// New symbol table entry\n  int nelems = -1;\t\t// Assume the number of elements won't be given\n  int maxelems;\t\t\t// The maximum number of elements in the init list\n  int *initlist;\t\t// The list of initial elements \n  int i = 0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems = parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class, 0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems = nelems;\n    else\n      maxelems = TABLE_INCREMENT;\n    initlist = (int *) malloc(maxelems * sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n\tfatal(\"Too many values in initialisation list\");\n\n      initlist[i++] = parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n\tmaxelems += TABLE_INCREMENT;\n\tinitlist = (int *) realloc(initlist, maxelems * sizeof(int));\n      }\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n\tscan(&Token);\n\tbreak;\n      }\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j = i; j < sym->nelems; j++)\n      initlist[j] = 0;\n    if (i > nelems)\n      nelems = i;\n    sym->initlist = initlist;\n  }\n  // Set the size of the array and the number of elements\n  sym->nelems = nelems;\n  sym->size = sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n\tparamcnt = 0;\n\tscan(&Token);\n\tbreak;\n      }\n    }\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, ctype, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree = optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t = declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t == -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead == NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name = NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n      if (findglob(varname) != NULL)\n\tfatals(\"Duplicate global variable declaration\", varname);\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree = NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n\tfatal(\"Function definition not at global level\");\n      return (type);\n    }\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree == NULL)\n      *gluetree = tree;\n    else\n      *gluetree =\n\tmkastnode(A_GLUE, P_NONE, NULL, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "52_Pointers_pt2/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int parentASTop);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nint alloc_register(void);\nvoid freeall_registers(int keepreg);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cglogor(int r1, int r2);\nint cglogand(int r1, int r2);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\nvoid dumptable(struct symtable *head, char *name, int indent);\nvoid dumpsymtables(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(struct symtable **ctype);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n                            struct symtable *rctype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "52_Pointers_pt2/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -w-ptr -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_QUESTION, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\t// 1\n  A_TERNARY, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\t\t// 6\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\t// 12\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\t\t\t// 20\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\t\t\t\t// 24\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\t\t\t// 28\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\t\t\t\t// 33\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\t\t\t// 37\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\t\t// 41\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\t\t// 46\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "52_Pointers_pt2/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree =\n      mkastnode(A_GLUE, P_NONE, NULL, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree =\n    mkastunary(A_FUNCCALL, funcptr->type, funcptr->ctype, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(struct ASTnode *left) {\n  struct ASTnode *right;\n\n  // Check that the sub-tree is a pointer\n  if (!ptrtype(left->type))\n    fatal(\"Not an array or pointer\");\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, left->ctype, A_ADD);\n\n  // Return an AST tree where the array's base has the offset added to it,\n  // and dereference the element. Still an lvalue at this point.\n  left =\n    mkastnode(A_ADD, left->type, left->ctype, left, NULL, right, NULL, 0);\n  left =\n    mkastunary(A_DEREF, value_at(left->type), left->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(struct ASTnode *left, int withpointer) {\n  struct ASTnode *right;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the left AST tree is a pointer to struct or union\n  if (withpointer && left->type != pointer_to(P_STRUCT)\n      && left->type != pointer_to(P_UNION))\n    fatal(\"Expression is not a pointer to a struct/union\");\n\n  // Or, check that the left AST tree is a struct or union.\n  // If so, change it from an A_IDENT to an A_ADDR so that\n  // we get the base address, not the value at this address.\n  if (!withpointer) {\n    if (left->type == P_STRUCT || left->type == P_UNION)\n      left->op = A_ADDR;\n    else\n      fatal(\"Expression is not a struct/union\");\n  }\n\n  // Get the details of the composite type\n  typeptr = left->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left =\n    mkastnode(A_ADD, pointer_to(m->type), m->ctype, left, NULL, right, NULL,\n\t      0);\n  left = mkastunary(A_DEREF, m->type, m->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse a parenthesised expression and\n// return an AST node representing it.\nstatic struct ASTnode *paren_expression(void) {\n  struct ASTnode *n;\n  int type = 0;\n  struct symtable *ctype = NULL;\n\n  // Beginning of a parenthesised expression, skip the '('.\n  scan(&Token);\n\n  // If the token after is a type identifier, this is a cast expression\n  switch (Token.token) {\n  case T_IDENT:\n    // We have to see if the identifier matches a typedef.\n    // If not, treat it as an expression.\n    if (findtypedef(Text) == NULL) {\n      n = binexpr(0);\n      break;\n    }\n  case T_VOID:\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n  case T_STRUCT:\n  case T_UNION:\n  case T_ENUM:\n    // Get the type inside the parentheses\n    type = parse_cast(&ctype);\n\n    // Skip the closing ')' and then parse the following expression\n    rparen();\n\n  default:\n    n = binexpr(0);\t\t// Scan in the expression\n  }\n\n  // We now have at least an expression in n, and possibly a non-zero type\n  // in type if there was a cast. Skip the closing ')' if there was no cast.\n  if (type == 0)\n    rparen();\n  else\n    // Otherwise, make a unary AST node for the cast\n    n = mkastunary(A_CAST, type, ctype, n, NULL, 0);\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  struct symtable *enumptr;\n  struct symtable *varptr;\n  int id;\n  int type = 0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type = parse_stars(parse_type(&ctype, &class));\n\n    // Get the type's size\n    size = typesize(type, ctype);\n    rparen();\n\n    // Make a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    // Then make a leaf AST node for it. id is the string's label.\n    id = genglobstr(Text);\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, NULL, id);\n    break;\n\n  case T_IDENT:\n    // If the identifier matches an enum value,\n    // return an A_INTLIT node\n    if ((enumptr = findenumval(Text)) != NULL) {\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, enumptr->st_posn);\n      break;\n    }\n    // See if this identifier exists as a symbol. For arrays, set rvalue to 1.\n    if ((varptr = findsymbol(Text)) == NULL)\n      fatals(\"Unknown variable or function\", Text);\n    switch (varptr->stype) {\n    case S_VARIABLE:\n      n = mkastleaf(A_IDENT, varptr->type, varptr->ctype, varptr, 0);\n      break;\n    case S_ARRAY:\n      n = mkastleaf(A_ADDR, varptr->type, varptr->ctype, varptr, 0);\n      n->rvalue = 1;\n      break;\n    case S_FUNCTION:\n      // Function call, see if the next token is a left parenthesis\n      scan(&Token);\n      if (Token.token != T_LPAREN)\n\tfatals(\"Function name used without parentheses\", Text);\n      return (funccall());\n    default:\n      fatals(\"Identifier not a scalar or array variable\", Text);\n    }\n    break;\n\n  case T_LPAREN:\n    return (paren_expression());\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n\n  // Get the primary expression\n  n = primary();\n\n  // Loop until there are no more postfix operators\n  while (1) {\n    switch (Token.token) {\n    case T_LBRACKET:\n      // An array reference\n      n = array_access(n);\n      break;\n\n    case T_DOT:\n      // Access into a struct or union\n      n = member_access(n, 0);\n      break;\n\n    case T_ARROW:\n      // Pointer access into a struct or union\n      n = member_access(n, 1);\n      break;\n\n    case T_INC:\n      // Post-increment: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot ++ on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTINC;\n      break;\n\n    case T_DEC:\n      // Post-decrement: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot -- on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTDEC;\n      break;\n\n    default:\n      return (n);\n    }\n  }\n\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatals(\"Token with no precedence in op_precedence:\", Tstring[tokentype]);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (prec);\n}\n\n// prefix_expression: postfix_expression\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Prevent '&' being performed on an array\n    if (tree->sym->stype == S_ARRAY)\n      fatal(\"& operator cannot be performed on an array\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree =\n      mkastunary(A_DEREF, value_at(tree->type), tree->ctype, tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this if needed to int so that it's signed\n    tree->rvalue = 1;\n    if (tree->type == P_CHAR)\n      tree->type = P_INT;\n    tree = mkastunary(A_NEGATE, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  default:\n    tree = postfix();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp = binexpr(0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. XXX We should also\n      // consider the third expression's type.\n      return (mkastnode\n\t      (A_TERNARY, right->type, right->ctype, left, right, ltemp,\n\t       NULL, 0));\n\n    case A_ASSIGN:\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, left->ctype, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n      break;\n\n    default:\n      // We are not doing a ternary or assignment, so both trees should\n      // be rvalues. Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, right->ctype, ASTop);\n      rtemp = modify_type(right, left->type, left->ctype, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left->ctype, left, NULL,\n\t\tright, NULL, 0);\n\n    // Some operators produce an int result regardless of their operands\n    switch (binastop(tokentype)) {\n    case A_LOGOR:\n    case A_LOGAND:\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      left->type = P_INT;\n    }\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs(reg);\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    if (c->left)\n      genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs(NOREG);\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    genfreeregs(NOREG);\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg, rightreg;\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_TERNARY:\n      return (gen_ternary(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL)\n\tgenAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs(NOREG);\n      if (n->right != NULL)\n\tgenAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs(NOREG);\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF, A_WHILE or A_TERNARY,\n      // generate a compare followed by a jump. Otherwise, compare\n      // registers and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE ||\n\t  parentASTop == A_TERNARY)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->a_intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->a_intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n\tcase A_ASPLUS:\n\t  leftreg = cgadd(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASMINUS:\n\t  leftreg = cgsub(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSTAR:\n\t  leftreg = cgmul(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSLASH:\n\t  leftreg = cgdiv(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL ||\n\t      n->right->sym->class == C_STATIC)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->a_size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL || n->left->sym->class == C_STATIC)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_LOGOR:\n      return (cglogor(leftreg, rightreg));\n    case A_LOGAND:\n      return (cglogand(leftreg, rightreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (leftreg);\t\t// Not much to do\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs(int keepreg) {\n  freeall_registers(keepreg);\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cgglobstr(l, strvalue);\n  return (l);\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "52_Pointers_pt2/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "52_Pointers_pt2/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "52_Pointers_pt2/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "52_Pointers_pt2/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "52_Pointers_pt2/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint fgetc(FILE *stream);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "52_Pointers_pt2/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "52_Pointers_pt2/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\nint strcmp(char *s1, char *s2);\nint strncmp(char *s1, char *s2, size_t n);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "52_Pointers_pt2/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "52_Pointers_pt2/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix;\n  posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Linestart = 1;\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token = 0;\t\t// and set there is no lookahead token\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n\n  // Dump the symbol table if requested\n  if (O_dumpsym) {\n    printf(\"Symbols for %s\\n\", filename);\n    dumpsymtables();\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcSTM] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -M dump the symbol table for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_dumpsym = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'M':\n\t  O_dumpsym = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  int i;\n  for (i = 0; s[i] != '\\0'; i++)\n    if (s[i] == (char) c)\n      return (i);\n  return (-1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (Linestart && c == '#') {\t// We've hit a pre-processor statement\n    Linestart = 0;\t\t// No longer at the start of the line\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n\n  Linestart = 0;\t\t// No longer at the start of the line\n  if ('\\n' == c) {\n    Line++;\t\t\t// Increment line count\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return n;\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn hexchar();\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, NULL, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, NULL, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, NULL, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree;\n\n  // Can't return a value if function returns P_VOID\n  if (Functionid->type == P_VOID)\n    fatal(\"Can't return from a void function\");\n\n  // Ensure we have 'return' '('\n  match(T_RETURN, \"return\");\n  lparen();\n\n  // Parse the following expression\n  tree = binexpr(0);\n\n  // Ensure this is compatible with the function's type\n  tree = modify_type(tree, Functionid->type, Functionid->ctype, 0);\n  if (tree == NULL)\n    fatal(\"Incompatible type to return\");\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, NULL, tree, NULL, 0);\n\n  // Get the ')' and ';'\n  rparen();\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, P_NONE, NULL, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, P_NONE, NULL, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *body, *n, *c;\n  struct ASTnode *casetree = NULL, *casetail;\n  int inloop = 1, casecount = 0;\n  int seendefault = 0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left = binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n = mkastunary(A_SWITCH, P_NONE, NULL, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch (Token.token) {\n\t// Leave the loop when we hit a '}'\n      case T_RBRACE:\n\tif (casecount == 0)\n\t  fatal(\"No cases in switch\");\n\tinloop = 0;\n\tbreak;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token == T_DEFAULT) {\n\t  ASTop = A_DEFAULT;\n\t  seendefault = 1;\n\t  scan(&Token);\n\t} else {\n\t  ASTop = A_CASE;\n\t  scan(&Token);\n\t  left = binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue = left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n\t  // that there isn't a duplicate case value\n\t  for (c = casetree; c != NULL; c = c->right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n\t}\n\n\t// Scan the ':' and increment the casecount\n\tmatch(T_COLON, \":\");\n\tcasecount++;\n\n\t// If the next token is a T_CASE, the existing case will fall\n\t// into the next case. Otherwise, parse the case body.\n\tif (Token.token == T_CASE)\n\t  body = NULL;\n\telse\n\t  body = compound_statement(1);\n\n\t// Build a sub-tree with any compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree == NULL) {\n\t  casetree = casetail =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t} else {\n\t  casetail->right =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t  casetail = casetail->right;\n\t}\n\tbreak;\n      default:\n\tfatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue = casecount;\n  n->right = casetree;\n  rbrace();\n\n  return (n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return (stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt = binexpr(0);\n\tsemi();\n\treturn (stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt = binexpr(0);\n      semi();\n      return (stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, NULL, left, NULL, tree, NULL, 0);\n    }\n    // Leave if we've hit the end token\n    if (Token.token == T_RBRACE)\n      return (left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT))\n      return (left);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n"
  },
  {
    "path": "52_Pointers_pt2/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list,\n\t\t\t\t      int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class == 0 || class == list->class)\n\treturn (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead = Globtail = NULL;\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Membhead = Membtail = NULL;\n  Structhead = Structtail = NULL;\n  Unionhead = Uniontail = NULL;\n  Enumhead = Enumtail = NULL;\n  Typehead = Typetail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev = NULL;\n\n  // Walk the global table looking for static entries\n  for (g = Globhead; g != NULL; g = g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL)\n\tprev->next = g->next;\n      else\n\tGlobhead->next = g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n\tif (prev != NULL)\n\t  Globtail = prev;\n\telse\n\t  Globtail = Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev = g;\n}\n\n// Dump a single symbol\nstatic void dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n    case P_VOID:\n      printf(\"void \");\n      break;\n    case P_CHAR:\n      printf(\"char \");\n      break;\n    case P_INT:\n      printf(\"int \");\n      break;\n    case P_LONG:\n      printf(\"long \");\n      break;\n    case P_STRUCT:\n      if (sym->ctype != NULL)\n\tprintf(\"struct %s \", sym->ctype->name);\n      else\n\tprintf(\"struct %s \", sym->name);\n      break;\n    case P_UNION:\n      if (sym->ctype != NULL)\n\tprintf(\"union %s \", sym->ctype->name);\n      else\n\tprintf(\"union %s \", sym->name);\n      break;\n    default:\n      printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++)\n    printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      break;\n    case S_FUNCTION:\n      printf(\"()\");\n      break;\n    case S_ARRAY:\n      printf(\"[]\");\n      break;\n    default:\n      printf(\" unknown stype\");\n  }\n\n  switch (sym->class) {\n    case C_GLOBAL:\n      printf(\": global\");\n      break;\n    case C_LOCAL:\n      printf(\": local\");\n      break;\n    case C_PARAM:\n      printf(\": param\");\n      break;\n    case C_EXTERN:\n      printf(\": extern\");\n      break;\n    case C_STATIC:\n      printf(\": static\");\n      break;\n    case C_STRUCT:\n      printf(\": struct\");\n      break;\n    case C_UNION:\n      printf(\": union\");\n      break;\n    case C_MEMBER:\n      printf(\": member\");\n      break;\n    case C_ENUMTYPE:\n      printf(\": enumtype\");\n      break;\n    case C_ENUMVAL:\n      printf(\": enumval\");\n      break;\n    case C_TYPEDEF:\n      printf(\": typedef\");\n      break;\n    default:\n      printf(\": unknown class\");\n  }\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      if (sym->class == C_ENUMVAL)\n\tprintf(\", value %d\\n\", sym->st_posn);\n      else\n\tprintf(\", size %d\\n\", sym->size);\n      break;\n    case S_FUNCTION:\n      printf(\", %d params\\n\", sym->nelems);\n      break;\n    case S_ARRAY:\n      printf(\", %d elems, size %d\\n\", sym->nelems, sym->size);\n      break;\n  }\n\n  switch (sym->type & (~0xf)) {\n    case P_STRUCT:\n    case P_UNION:\n      dumptable(sym->member, NULL, 4);\n  }\n\n  switch (sym->stype) {\n    case S_FUNCTION:\n      dumptable(sym->member, NULL, 4);\n  }\n}\n\n// Dump one symbol table\nvoid dumptable(struct symtable *head, char *name, int indent) {\n  struct symtable *sym;\n\n  if (head != NULL && name != NULL)\n    printf(\"%s\\n--------\\n\", name);\n  for (sym = head; sym != NULL; sym = sym->next)\n    dumpsym(sym, indent);\n}\n\nvoid dumpsymtables(void) {\n  dumptable(Globhead, \"Global\", 0);\n  printf(\"\\n\");\n  dumptable(Enumhead, \"Enums\", 0);\n  printf(\"\\n\");\n  dumptable(Typehead, \"Typedefs\", 0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input032.c",
    "content": "Unknown variable or function:pizza on line 4 of input032.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input042.c",
    "content": "Unknown variable or function:fred on line 3 of input042.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input043.c",
    "content": "Unknown variable or function:b on line 3 of input043.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input044.c",
    "content": "Unknown variable or function:z on line 3 of input044.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input059.c",
    "content": "Unknown variable or function:y on line 3 of input059.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input060.c",
    "content": "Expression is not a struct/union on line 3 of input060.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input061.c",
    "content": "Expression is not a pointer to a struct/union on line 3 of input061.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input093.c",
    "content": "Unknown variable or function:fred on line 1 of input093.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input124.c",
    "content": "Cannot ++ on rvalue on line 6 of input124.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input126.c",
    "content": "Unknown variable or function:ptr on line 7 of input126.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/err.input129.c",
    "content": "Cannot ++ and/or -- more than once on line 6 of input129.c\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input122.c",
    "content": "#include <stdio.h>\n\nint x, y, z1, z2;\n\nint main() {\n  for (x= 0; x <= 1; x++) {\n    for (y= 0; y <= 1; y++) {\n      z1= x || y; z2= x && y;\n      printf(\"x %d, y %d, x || y %d, x && y %d\\n\", x, y, z1, z2);\n    }\n  }\n  \n  //z= x || y;\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input123.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  for (x=0; x < 20; x++)\n    switch(x) {\n      case 2:\n      case 3:\n      case 5:\n      case 7:\n      case 11: printf(\"%2d infant prime\\n\", x); break;\n      case 13:\n      case 17:\n      case 19: printf(\"%2d teen   prime\\n\", x); break;\n      case 0:\n      case 1:\n      case 4:\n      case 6:\n      case 8:\n      case 9:\n      case 10:\n      case 12: printf(\"%2d infant composite\\n\", x); break;\n      default: printf(\"%2d teen   composite\\n\", x); break;\n    }\n\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input124.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary++;\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input125.c",
    "content": "#include <stdio.h>\n\nint ary[5];\nint *ptr;\nint x;\n\nint main() {\n  ary[3]= 2008;\n  ptr= ary;\t\t\t// Load ary's address into ptr\n  x= ary[3]; printf(\"%d\\n\", x);\n  x= ptr[3]; printf(\"%d\\n\", x); // Treat ptr as an array\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input126.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary[3]= 2008;\n  ptr= &ary;\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input127.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nvoid fred(int *ptr) {\t\t// Receive a pointer\n  printf(\"%d\\n\", ptr[3]);\n}\n\nint main() {\n  ary[3]= 2008;\n  printf(\"%d\\n\", ary[3]);\n  fred(ary);\t\t\t// Pass ary as a pointer\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input128.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int val;\n  struct foo *next;\n};\n\nstruct foo head, mid, tail;\n\nint main() {\n  struct foo *ptr;\n  tail.val= 20; tail.next= NULL;\n  mid.val= 15; mid.next= &tail;\n  head.val= 10; head.next= &mid;\n\n  ptr= &head;\n  printf(\"%d %d\\n\", head.val, ptr->val);\n  printf(\"%d %d\\n\", mid.val, ptr->next->val);\n  printf(\"%d %d\\n\", tail.val, ptr->next->next->val);\n  return(0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/input129.c",
    "content": "#include <stdio.h>\n\nint x= 6;\n\nint main() {\n  printf(\"%d\\n\", x++ ++);\n  return(0);\n}\n\n"
  },
  {
    "path": "52_Pointers_pt2/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "52_Pointers_pt2/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input122.c",
    "content": "x 0, y 0, x || y 0, x && y 0\nx 0, y 1, x || y 1, x && y 0\nx 1, y 0, x || y 1, x && y 0\nx 1, y 1, x || y 1, x && y 1\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input123.c",
    "content": " 0 infant composite\n 1 infant composite\n 2 infant prime\n 3 infant prime\n 4 infant composite\n 5 infant prime\n 6 infant composite\n 7 infant prime\n 8 infant composite\n 9 infant composite\n10 infant composite\n11 infant prime\n12 infant composite\n13 teen   prime\n14 teen   composite\n15 teen   composite\n16 teen   composite\n17 teen   prime\n18 teen   composite\n19 teen   prime\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input125.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input127.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "52_Pointers_pt2/tests/out.input128.c",
    "content": "10 10\n15 15\n20 20\n"
  },
  {
    "path": "52_Pointers_pt2/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "52_Pointers_pt2/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "52_Pointers_pt2/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->ctype = ctype;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n  int i;\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (int i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (int i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "52_Pointers_pt2/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n\t\t\t    struct symtable *rctype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, NULL, tree, NULL, 0));\n  }\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return (tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, rctype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "53_Mop_up_pt2/Readme.md",
    "content": "# Part 53: Mopping Up, part 2\n\nIn this part of our compiler writing journey, I fix a few annoying things\nthat we use in the compiler's own source code.\n\n## Consecutive String Literals\n\nC allows the declaration of string literals by splitting them across\nmultiple lines or as multiple strings, e.g.\n\n```c\n  char *c= \"hello \" \"there, \"\n           \"how \" \"are \" \"you?\";\n```\n\nNow, we could fix this problem up in the lexical scanner. However, I spent\na lot of time trying to do this. The problem is that the code is now\ncomplicated with dealing with the C pre-processor, and I couldn't find a clean\nway of allowing consecutive string literals.\n\nMy solution is to do it in the parser, with a bit of help from the code\ngenerator. In `primary()` in `expr.c`, the code that deals with string\nliterals now looks like this:\n\n```c\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    id = genglobstr(Text, 0);   // 0 means generate a label\n\n    // For successive STRLIT tokens, append their contents\n    // to this one\n    while (1) {\n      scan(&Peektoken);\n      if (Peektoken.token != T_STRLIT) break;\n      genglobstr(Text, 1);      // 1 means don't generate a label\n      scan(&Token);             // Skip it\n    }\n\n    // Now make a leaf AST node for it. id is the string's label.\n    genglobstrend();\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, NULL, id);\n    break;\n```\n\n`genglobstr()` now takes a second argument which tells it if this\nis the first part of the string or a successive part of the string.\nAlso, `genglobstrend()` now has the job of NUL terminating the string literal.\n\n## Empty Statements\n\nC allows both empty statements and empty compound statements, e.g.\n\n```c\n  while ((c=getc()) != 'x') ;           // ';' is an empty statement\n\n  int fred() { }                        // Function with empty body\n```\n\nand I use both of these in the compiler, so we need to support both of them.\nIn `stmt.c`, the code now does this:\n\n```c\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_SEMI:\n      // An empty statement\n      semi();\n      break;\n    ...\n  }\n  ...\n}\n\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Leave if we've hit the end token. We do this first to allow\n    // an empty compound statement\n    if (Token.token == T_RBRACE)\n      return (left);\n    ...\n  }\n  ...\n}\n```\n\nand that fixes both shortcomings.\n\n## Redeclared Symbols\n\nC allows a global variable to later be declared extern, and an extern\nvariable to be declared later as a global variable, and vice versa.\nHowever, the types of both\ndeclarations have to match. We also want to ensure that only one\nversion of the symbol ends up in the symbol table: we don't want both a\nC_GLOBAL and a C_EXTERN entry!\n\nIn `stmt.c` I've added a new function called `is_new_symbol()`. We call this\nafter we have parsed the name of a variable and after we have tried\nto find it in the symbol table. Thus, `sym` may be NULL (no existing\nvariable) or not NULL (is an existing variable).\n\nIf the symbol exists, it's actually quite complicated to ensure that\nit's a safe redeclaration.\n\n```c\n// Given a pointer to a symbol that may already exist\n// return true if this symbol doesn't exist. We use\n// this function to convert externs into globals\nint is_new_symbol(struct symtable *sym, int class, \n                  int type, struct symtable *ctype) {\n\n  // There is no existing symbol, thus is new\n  if (sym==NULL) return(1);\n\n  // global versus extern: if they match that it's not new\n  // and we can convert the class to global\n  if ((sym->class== C_GLOBAL && class== C_EXTERN)\n      || (sym->class== C_EXTERN && class== C_GLOBAL)) {\n\n      // If the types don't match, there's a problem\n      if (type != sym->type)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // Struct/unions, also compare the ctype\n      if (type >= P_STRUCT && ctype != sym->ctype)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // If we get to here, the types match, so mark the symbol\n      // as global\n      sym->class= C_GLOBAL;\n      // Return that symbol is not new\n      return(0);\n  }\n\n  // It must be a duplicate symbol if we get here\n  fatals(\"Duplicate global variable declaration\", sym->name);\n  return(-1);   // Keep -Wall happy\n}\n```\n\nThe code is straight-forward but not elegant. Also note that any redeclared\nextern symbol is turned into a global symbol. This means we don't have to\nremove the symbol from the symbol table and add in a new, global, symbol.\n\n## Operand Types to Logical Operations\n\nThe next bug I hit was something like this:\n\n```c\n  int *x;\n  int y;\n\n  if (x && y > 12) ...\n```\n\nThe compiler evaluates the `&&` operation in `binexpr()`. To do this,\nit ensures that the types of each side of the binary operator are\ncompatible. Well, if the operator above was a `+` then, definitely,\nthe types are incompatible. But with a logical comparison, we can\n*AND* these together.\n\nI've fixed this by adding some more code to the top of `modify_type()`\nin `types.c`. If we are doing an `&&` or an `||` operation, then\nwe need either integer or pointer types on each side of the operation.\n\n```c\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n                            struct symtable *rctype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // For A_LOGOR and A_LOGAND, both types have to be int or pointer types\n  if (op==A_LOGOR || op==A_LOGAND) {\n    if (!inttype(ltype) && !ptrtype(ltype))\n      return(NULL);\n    if (!inttype(ltype) && !ptrtype(rtype))\n      return(NULL);\n    return (tree);\n  }\n  ...\n}\n```\n\nI've also realised that I've implemented `&&` and `||` incorrectly, so\nI'll have to fix that. Now now, but soon.\n\n## Return with No Value\n\nOne other C feature that is missing is the ability to return from a\nvoid function, i.e. just leave without returning any value. However,\nthe current parser expects to see parentheses and an expression after\nthe `return` keyword.\n\nSo, in `return_statement()` in `stmt.c`, we now have:\n\n```c\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree= NULL;\n\n  // Ensure we have 'return'\n  match(T_RETURN, \"return\");\n\n  // See if we have a return value\n  if (Token.token == T_LPAREN) {\n    // Code to parse the parentheses and the expression\n    ...\n  } else {\n    if (Functionid->type != P_VOID)\n      fatal(\"Must return a value from a non-void function\");\n  }\n\n\n    // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, NULL, tree, NULL, 0);\n\n  // Get the ';'\n  semi();\n  return (tree);\n}\n```\n\nIf the `return` token isn't followed by a left parenthesis, we leave the\nexpression `tree` set to NULL. We also check that this is a void returning\nfunction, and print out a fatal error if not.\n\nNow that we have parsed the `return` function, we may create an A_RETURN\nAST node with a NULL child. So now we have to deal with this in the code\ngenerator. The top of `cgreturn()` in `cg.c` now has:\n\n```c\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    ..\n  }\n\n  cgjump(sym->st_endlabel);\n}\n```\n\nIf there was no child AST tree, then there is no register with the\nexpression's value. Thus, we only output the jump to the function's\nend label.\n\n\n## Conclusion and What's Next\n\nWe've fixed five minor issues in the compiler: things that we need to work to get\nthe compiler to compile itself.\n\nI did identify a problem with `&&` and `||`. However, before we get to\nthat I need to solve an important, pressing, problem: we have a limited\nset of CPU registers and, for large source files, we are running out of\nthem.\n\nIn the next part of our compiler writing journey, I will have to work\non implementing register spills. I've been delaying this, but now most of\nthe fatal errors from the compiler (when compiling itself) are register\nissues. So now it's time to sort this out. [Next step](../54_Reg_Spills/Readme.md)\n"
  },
  {
    "path": "53_Mop_up_pt2/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n\tfatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\" \"\\t.type\\t%s, @function\\n\", name, name);\n  fprintf(Outfile, \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\" \"\\tmovq\\t%%rsp, %%rbp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn,\n\t\treglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn,\n\t\treglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Logically OR two registers and return a\n// register with the result, 1 or 0\nint cglogor(int r1, int r2) {\n  // Generate two labels\n  int Ltrue = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Test r2 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Didn't jump, so result is false\n  fprintf(Outfile, \"\\tmovq\\t$0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the true label, so result is true\n  cglabel(Ltrue);\n  fprintf(Outfile, \"\\tmovq\\t$1, %s\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return (r1);\n}\n\n// Logically AND two registers and return a\n// register with the result, 1 or 0\nint cglogand(int r1, int r2) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Test r2 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Didn't jump, so result is true\n  fprintf(Outfile, \"\\tmovq\\t$1, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the false label, so result is false\n  cglabel(Lfalse);\n  fprintf(Outfile, \"\\tmovq\\t$0, %s\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return (r1);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r],\n\t\tsym->st_posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r],\n\t\tsym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n      case 1:\n\tfprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n\tbreak;\n      case 8:\n\t// Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n\tif (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t    && initvalue != 0)\n\t  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n\telse\n\t  fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n\tbreak;\n      default:\n\tfor (i = 0; i < size; i++)\n\t  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n        case P_CHAR:\n\t  fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n\t  break;\n        case P_INT:\n\t  fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n\t  break;\n        case P_LONG:\n\t  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n\t  break;\n        default:\n\t  fatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Set all registers as available\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", name);\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r1);\n  return (r2);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Logically OR two registers and return a\n// register with the result, 1 or 0\nint cglogor(int r1, int r2) {\n  // Generate two labels\n  int Ltrue = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Test r2 and jump to true label if true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tjne\\tL%d\\n\", Ltrue);\n\n  // Didn't jump, so result is false\n  fprintf(Outfile, \"\\tmov\\t%s, 0\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the true label, so result is true\n  cglabel(Ltrue);\n  fprintf(Outfile, \"\\tmov\\t%s, 1\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n\n// Logically AND two registers and return a\n// register with the result, 1 or 0\nint cglogand(int r1, int r2) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n\n  // Test r1 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r1], reglist[r1]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Test r2 and jump to false label if not true\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  fprintf(Outfile, \"\\tje\\tL%d\\n\", Lfalse);\n\n  // Didn't jump, so result is true\n  fprintf(Outfile, \"\\tmov\\t%s, 1\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", Lend);\n\n  // Someone jumped to the false label, so result is false\n  cglabel(Lfalse);\n  fprintf(Outfile, \"\\tmov\\t%s, 0\\n\", reglist[r1]);\n  cglabel(Lend);\n  free_register(r2);\n  return(r1);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF or WHILE operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  if (op == A_IF || op == A_WHILE)\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n  else {\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  // Get a new register\n  int outr = alloc_register();\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // and copy the return value into our register\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n        case P_CHAR:\n          fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n          break;\n        case P_INT:\n          fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n          break;\n        case P_LONG:\n          fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n          break;\n        default:\n          fatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Linestart;\t\t     \t// True if at start of a line\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\nextern char *Tstring[];\t\t\t// List of token strings\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_dumpsym;\t\t// If true, dump the symbol table\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "53_Mop_up_pt2/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Get the type inside the parentheses\n  type = parse_stars(parse_type(ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return (type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree = optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type = tree->type;\n    tree = tree->left;\n  }\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return (tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue == 0)\n      return (0);\n  }\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return (tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a pointer to a symbol that may already exist\n// return true if this symbol doesn't exist. We use\n// this function to convert externs into globals\nint is_new_symbol(struct symtable *sym, int class, \n\t\t  int type, struct symtable *ctype) {\n\n  // There is no existing symbol, thus is new\n  if (sym==NULL) return(1);\n\n  // global versus extern: if they match that it's not new\n  // and we can convert the class to global\n  if ((sym->class== C_GLOBAL && class== C_EXTERN)\n      || (sym->class== C_EXTERN && class== C_GLOBAL)) {\n\n      // If the types don't match, there's a problem\n      if (type != sym->type)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // Struct/unions, also compare the ctype\n      if (type >= P_STRUCT && ctype != sym->ctype)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // If we get to here, the types match, so mark the symbol\n      // as global\n      sym->class= C_GLOBAL;\n      // Return that symbol is not new\n      return(0);\n  }\n\n  // It must be a duplicate symbol if we get here\n  fatals(\"Duplicate global variable declaration\", sym->name);\n  return(-1);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree = NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, type, ctype))\n        sym = addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym = addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym = addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist = (int *) malloc(sizeof(int));\n      sym->initlist[0] = parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym->ctype, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, varnode->ctype, 0);\n      if (exprnode == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode->ctype, exprnode,\n\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t\t// New symbol table entry\n  int nelems = -1;\t\t// Assume the number of elements won't be given\n  int maxelems;\t\t\t// The maximum number of elements in the init list\n  int *initlist;\t\t// The list of initial elements \n  int i = 0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems = parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, pointer_to(type), ctype))\n        sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class, 0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems = nelems;\n    else\n      maxelems = TABLE_INCREMENT;\n    initlist = (int *) malloc(maxelems * sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n\tfatal(\"Too many values in initialisation list\");\n\n      initlist[i++] = parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n\tmaxelems += TABLE_INCREMENT;\n\tinitlist = (int *) realloc(initlist, maxelems * sizeof(int));\n      }\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n\tscan(&Token);\n\tbreak;\n      }\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j = i; j < sym->nelems; j++)\n      initlist[j] = 0;\n    if (i > nelems)\n      nelems = i;\n    sym->initlist = initlist;\n  }\n  // Set the size of the array and the number of elements\n  sym->nelems = nelems;\n  sym->size = sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n\tparamcnt = 0;\n\tscan(&Token);\n\tbreak;\n      }\n    }\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, ctype, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree = optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t = declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t == -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead == NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name = NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree = NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n\tfatal(\"Function definition not at global level\");\n      return (type);\n    }\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree == NULL)\n      *gluetree = tree;\n    else\n      *gluetree =\n\tmkastnode(A_GLUE, P_NONE, NULL, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype= NULL;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int level);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue, int append);\nvoid genglobstrend(void);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nint alloc_register(void);\nvoid freeall_registers(int keepreg);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue, int append);\nvoid cgglobstrend(void);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nint cglogor(int r1, int r2);\nint cglogand(int r1, int r2);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\nvoid dumptable(struct symtable *head, char *name, int indent);\nvoid dumpsymtables(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(struct symtable **ctype);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n                            struct symtable *rctype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "53_Mop_up_pt2/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -w-ptr -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_QUESTION, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\t// 1\n  A_TERNARY, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\t\t// 6\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\t// 12\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\t\t\t// 20\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\t\t\t\t// 24\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\t\t\t// 28\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\t\t\t\t// 33\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\t\t\t// 37\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\t\t// 41\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\t\t// 46\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "53_Mop_up_pt2/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree =\n      mkastnode(A_GLUE, P_NONE, NULL, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree =\n    mkastunary(A_FUNCCALL, funcptr->type, funcptr->ctype, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(struct ASTnode *left) {\n  struct ASTnode *right;\n\n  // Check that the sub-tree is a pointer\n  if (!ptrtype(left->type))\n    fatal(\"Not an array or pointer\");\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, left->ctype, A_ADD);\n\n  // Return an AST tree where the array's base has the offset added to it,\n  // and dereference the element. Still an lvalue at this point.\n  left =\n    mkastnode(A_ADD, left->type, left->ctype, left, NULL, right, NULL, 0);\n  left =\n    mkastunary(A_DEREF, value_at(left->type), left->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(struct ASTnode *left, int withpointer) {\n  struct ASTnode *right;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the left AST tree is a pointer to struct or union\n  if (withpointer && left->type != pointer_to(P_STRUCT)\n      && left->type != pointer_to(P_UNION))\n    fatal(\"Expression is not a pointer to a struct/union\");\n\n  // Or, check that the left AST tree is a struct or union.\n  // If so, change it from an A_IDENT to an A_ADDR so that\n  // we get the base address, not the value at this address.\n  if (!withpointer) {\n    if (left->type == P_STRUCT || left->type == P_UNION)\n      left->op = A_ADDR;\n    else\n      fatal(\"Expression is not a struct/union\");\n  }\n\n  // Get the details of the composite type\n  typeptr = left->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left =\n    mkastnode(A_ADD, pointer_to(m->type), m->ctype, left, NULL, right, NULL,\n\t      0);\n  left = mkastunary(A_DEREF, m->type, m->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse a parenthesised expression and\n// return an AST node representing it.\nstatic struct ASTnode *paren_expression(void) {\n  struct ASTnode *n;\n  int type = 0;\n  struct symtable *ctype = NULL;\n\n  // Beginning of a parenthesised expression, skip the '('.\n  scan(&Token);\n\n  // If the token after is a type identifier, this is a cast expression\n  switch (Token.token) {\n  case T_IDENT:\n    // We have to see if the identifier matches a typedef.\n    // If not, treat it as an expression.\n    if (findtypedef(Text) == NULL) {\n      n = binexpr(0);\n      break;\n    }\n  case T_VOID:\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n  case T_STRUCT:\n  case T_UNION:\n  case T_ENUM:\n    // Get the type inside the parentheses\n    type = parse_cast(&ctype);\n\n    // Skip the closing ')' and then parse the following expression\n    rparen();\n\n  default:\n    n = binexpr(0);\t\t// Scan in the expression\n  }\n\n  // We now have at least an expression in n, and possibly a non-zero type\n  // in type if there was a cast. Skip the closing ')' if there was no cast.\n  if (type == 0)\n    rparen();\n  else\n    // Otherwise, make a unary AST node for the cast\n    n = mkastunary(A_CAST, type, ctype, n, NULL, 0);\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  struct symtable *enumptr;\n  struct symtable *varptr;\n  int id;\n  int type = 0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type = parse_stars(parse_type(&ctype, &class));\n\n    // Get the type's size\n    size = typesize(type, ctype);\n    rparen();\n\n    // Make a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    id = genglobstr(Text, 0);\n\n    // For successive STRLIT tokens, append their contents\n    // to this one\n    while (1) {\n      scan(&Peektoken);\n      if (Peektoken.token != T_STRLIT) break;\n      genglobstr(Text, 1);\n      scan(&Token);\t// To skip it properly\n    }\n\n    // Now make a leaf AST node for it. id is the string's label.\n    genglobstrend();\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, NULL, id);\n    break;\n\n  case T_IDENT:\n    // If the identifier matches an enum value,\n    // return an A_INTLIT node\n    if ((enumptr = findenumval(Text)) != NULL) {\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, enumptr->st_posn);\n      break;\n    }\n    // See if this identifier exists as a symbol. For arrays, set rvalue to 1.\n    if ((varptr = findsymbol(Text)) == NULL)\n      fatals(\"Unknown variable or function\", Text);\n    switch (varptr->stype) {\n    case S_VARIABLE:\n      n = mkastleaf(A_IDENT, varptr->type, varptr->ctype, varptr, 0);\n      break;\n    case S_ARRAY:\n      n = mkastleaf(A_ADDR, varptr->type, varptr->ctype, varptr, 0);\n      n->rvalue = 1;\n      break;\n    case S_FUNCTION:\n      // Function call, see if the next token is a left parenthesis\n      scan(&Token);\n      if (Token.token != T_LPAREN)\n\tfatals(\"Function name used without parentheses\", Text);\n      return (funccall());\n    default:\n      fatals(\"Identifier not a scalar or array variable\", Text);\n    }\n    break;\n\n  case T_LPAREN:\n    return (paren_expression());\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n\n  // Get the primary expression\n  n = primary();\n\n  // Loop until there are no more postfix operators\n  while (1) {\n    switch (Token.token) {\n    case T_LBRACKET:\n      // An array reference\n      n = array_access(n);\n      break;\n\n    case T_DOT:\n      // Access into a struct or union\n      n = member_access(n, 0);\n      break;\n\n    case T_ARROW:\n      // Pointer access into a struct or union\n      n = member_access(n, 1);\n      break;\n\n    case T_INC:\n      // Post-increment: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot ++ on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTINC;\n      break;\n\n    case T_DEC:\n      // Post-decrement: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot -- on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTDEC;\n      break;\n\n    default:\n      return (n);\n    }\n  }\n\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatals(\"Token with no precedence in op_precedence:\", Tstring[tokentype]);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (prec);\n}\n\n// prefix_expression: postfix_expression\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Prevent '&' being performed on an array\n    if (tree->sym->stype == S_ARRAY)\n      fatal(\"& operator cannot be performed on an array\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree =\n      mkastunary(A_DEREF, value_at(tree->type), tree->ctype, tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this if needed to int so that it's signed\n    tree->rvalue = 1;\n    if (tree->type == P_CHAR)\n      tree->type = P_INT;\n    tree = mkastunary(A_NEGATE, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  default:\n    tree = postfix();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp = binexpr(0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. XXX We should also\n      // consider the third expression's type.\n      return (mkastnode\n\t      (A_TERNARY, right->type, right->ctype, left, right, ltemp,\n\t       NULL, 0));\n\n    case A_ASSIGN:\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, left->ctype, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n      break;\n\n    default:\n      // We are not doing a ternary or assignment, so both trees should\n      // be rvalues. Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, right->ctype, ASTop);\n      rtemp = modify_type(right, left->type, left->ctype, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left->ctype, left, NULL,\n\t\tright, NULL, 0);\n\n    // Some operators produce an int result regardless of their operands\n    switch (binastop(tokentype)) {\n    case A_LOGOR:\n    case A_LOGAND:\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      left->type = P_INT;\n    }\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs(reg);\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    if (c->left)\n      genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs(NOREG);\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    genfreeregs(NOREG);\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg= NOREG, rightreg= NOREG;\n\n  // Empty tree, do nothing\n  if (n==NULL) return(NOREG);\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_TERNARY:\n      return (gen_ternary(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL)\n\tgenAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs(NOREG);\n      if (n->right != NULL)\n\tgenAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs(NOREG);\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF, A_WHILE or A_TERNARY,\n      // generate a compare followed by a jump. Otherwise, compare\n      // registers and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE ||\n\t  parentASTop == A_TERNARY)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->a_intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->a_intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n\tcase A_ASPLUS:\n\t  leftreg = cgadd(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASMINUS:\n\t  leftreg = cgsub(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSTAR:\n\t  leftreg = cgmul(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSLASH:\n\t  leftreg = cgdiv(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL ||\n\t      n->right->sym->class == C_STATIC)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->a_size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL || n->left->sym->class == C_STATIC)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_LOGOR:\n      return (cglogor(leftreg, rightreg));\n    case A_LOGAND:\n      return (cglogand(leftreg, rightreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (leftreg);\t\t// Not much to do\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs(int keepreg) {\n  freeall_registers(keepreg);\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\n\n// Generate a global string.\n// If append is true, append to\n// previous genglobstr() call.\nint genglobstr(char *strvalue, int append) {\n  int l = genlabel();\n  cgglobstr(l, strvalue, append);\n  return (l);\n}\nvoid genglobstrend(void) {\n  cgglobstrend();\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\nint toupper(int c);\nint tolower(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "53_Mop_up_pt2/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "53_Mop_up_pt2/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "53_Mop_up_pt2/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "53_Mop_up_pt2/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n#ifndef EOF\n# define EOF (-1)\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint fgetc(FILE *stream);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "53_Mop_up_pt2/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "53_Mop_up_pt2/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\nint strcmp(char *s1, char *s2);\nint strncmp(char *s1, char *s2, size_t n);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "53_Mop_up_pt2/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "53_Mop_up_pt2/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix;\n  posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Linestart = 1;\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token = 0;\t\t// and set there is no lookahead token\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n\n  // Dump the symbol table if requested\n  if (O_dumpsym) {\n    printf(\"Symbols for %s\\n\", filename);\n    dumpsymtables();\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcSTM] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -M dump the symbol table for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_dumpsym = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'M':\n\t  O_dumpsym = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  int i;\n  for (i = 0; s[i] != '\\0'; i++)\n    if (s[i] == (char) c)\n      return (i);\n  return (-1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (Linestart && c == '#') {\t// We've hit a pre-processor statement\n    Linestart = 0;\t\t// No longer at the start of the line\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n\n  Linestart = 0;\t\t// No longer at the start of the line\n  if ('\\n' == c) {\n    Line++;\t\t\t// Increment line count\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return (n);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn (hexchar());\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = (char)c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = (char)c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, NULL, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, NULL, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, NULL, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree= NULL;\n\n  // Ensure we have 'return'\n  match(T_RETURN, \"return\");\n\n  // See if we have a return value\n  if (Token.token == T_LPAREN) {\n    // Can't return a value if function returns P_VOID\n    if (Functionid->type == P_VOID)\n      fatal(\"Can't return from a void function\");\n\n    // Skip the left parenthesis\n    lparen();\n\n    // Parse the following expression\n    tree = binexpr(0);\n\n    // Ensure this is compatible with the function's type\n    tree = modify_type(tree, Functionid->type, Functionid->ctype, 0);\n    if (tree == NULL)\n      fatal(\"Incompatible type to return\");\n\n    // Get the ')'\n    rparen();\n  } else {\n    if (Functionid->type != P_VOID)\n      fatal(\"Must return a value from a non-void function\");\n  }\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, NULL, tree, NULL, 0);\n\n  // Get the ';'\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, P_NONE, NULL, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, P_NONE, NULL, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *body, *n, *c;\n  struct ASTnode *casetree = NULL, *casetail;\n  int inloop = 1, casecount = 0;\n  int seendefault = 0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left = binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n = mkastunary(A_SWITCH, P_NONE, NULL, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch (Token.token) {\n\t// Leave the loop when we hit a '}'\n      case T_RBRACE:\n\tif (casecount == 0)\n\t  fatal(\"No cases in switch\");\n\tinloop = 0;\n\tbreak;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token == T_DEFAULT) {\n\t  ASTop = A_DEFAULT;\n\t  seendefault = 1;\n\t  scan(&Token);\n\t} else {\n\t  ASTop = A_CASE;\n\t  scan(&Token);\n\t  left = binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue = left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n\t  // that there isn't a duplicate case value\n\t  for (c = casetree; c != NULL; c = c->right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n\t}\n\n\t// Scan the ':' and increment the casecount\n\tmatch(T_COLON, \":\");\n\tcasecount++;\n\n\t// If the next token is a T_CASE, the existing case will fall\n\t// into the next case. Otherwise, parse the case body.\n\tif (Token.token == T_CASE)\n\t  body = NULL;\n\telse\n\t  body = compound_statement(1);\n\n\t// Build a sub-tree with any compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree == NULL) {\n\t  casetree = casetail =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t} else {\n\t  casetail->right =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t  casetail = casetail->right;\n\t}\n\tbreak;\n      default:\n\tfatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue = casecount;\n  n->right = casetree;\n  rbrace();\n\n  return (n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_SEMI:\n      // An empty statement\n      semi();\n      break;\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return (stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt = binexpr(0);\n\tsemi();\n\treturn (stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt = binexpr(0);\n      semi();\n      return (stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Leave if we've hit the end token. We do this first to allow\n    // an empty compound statement\n    if (Token.token == T_RBRACE)\n      return (left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT))\n      return (left);\n\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, NULL, left, NULL, tree, NULL, 0);\n    }\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list,\n\t\t\t\t      int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class == 0 || class == list->class)\n\treturn (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead = Globtail = NULL;\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Membhead = Membtail = NULL;\n  Structhead = Structtail = NULL;\n  Unionhead = Uniontail = NULL;\n  Enumhead = Enumtail = NULL;\n  Typehead = Typetail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev = NULL;\n\n  // Walk the global table looking for static entries\n  for (g = Globhead; g != NULL; g = g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL)\n\tprev->next = g->next;\n      else\n\tGlobhead->next = g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n\tif (prev != NULL)\n\t  Globtail = prev;\n\telse\n\t  Globtail = Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev = g;\n}\n\n// Dump a single symbol\nstatic void dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n    case P_VOID:\n      printf(\"void \");\n      break;\n    case P_CHAR:\n      printf(\"char \");\n      break;\n    case P_INT:\n      printf(\"int \");\n      break;\n    case P_LONG:\n      printf(\"long \");\n      break;\n    case P_STRUCT:\n      if (sym->ctype != NULL)\n\tprintf(\"struct %s \", sym->ctype->name);\n      else\n\tprintf(\"struct %s \", sym->name);\n      break;\n    case P_UNION:\n      if (sym->ctype != NULL)\n\tprintf(\"union %s \", sym->ctype->name);\n      else\n\tprintf(\"union %s \", sym->name);\n      break;\n    default:\n      printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++)\n    printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      break;\n    case S_FUNCTION:\n      printf(\"()\");\n      break;\n    case S_ARRAY:\n      printf(\"[]\");\n      break;\n    default:\n      printf(\" unknown stype\");\n  }\n\n  switch (sym->class) {\n    case C_GLOBAL:\n      printf(\": global\");\n      break;\n    case C_LOCAL:\n      printf(\": local\");\n      break;\n    case C_PARAM:\n      printf(\": param\");\n      break;\n    case C_EXTERN:\n      printf(\": extern\");\n      break;\n    case C_STATIC:\n      printf(\": static\");\n      break;\n    case C_STRUCT:\n      printf(\": struct\");\n      break;\n    case C_UNION:\n      printf(\": union\");\n      break;\n    case C_MEMBER:\n      printf(\": member\");\n      break;\n    case C_ENUMTYPE:\n      printf(\": enumtype\");\n      break;\n    case C_ENUMVAL:\n      printf(\": enumval\");\n      break;\n    case C_TYPEDEF:\n      printf(\": typedef\");\n      break;\n    default:\n      printf(\": unknown class\");\n  }\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      if (sym->class == C_ENUMVAL)\n\tprintf(\", value %d\\n\", sym->st_posn);\n      else\n\tprintf(\", size %d\\n\", sym->size);\n      break;\n    case S_FUNCTION:\n      printf(\", %d params\\n\", sym->nelems);\n      break;\n    case S_ARRAY:\n      printf(\", %d elems, size %d\\n\", sym->nelems, sym->size);\n      break;\n  }\n\n  switch (sym->type & (~0xf)) {\n    case P_STRUCT:\n    case P_UNION:\n      dumptable(sym->member, NULL, 4);\n  }\n\n  switch (sym->stype) {\n    case S_FUNCTION:\n      dumptable(sym->member, NULL, 4);\n  }\n}\n\n// Dump one symbol table\nvoid dumptable(struct symtable *head, char *name, int indent) {\n  struct symtable *sym;\n\n  if (head != NULL && name != NULL)\n    printf(\"%s\\n--------\\n\", name);\n  for (sym = head; sym != NULL; sym = sym->next)\n    dumpsym(sym, indent);\n}\n\nvoid dumpsymtables(void) {\n  dumptable(Globhead, \"Global\", 0);\n  printf(\"\\n\");\n  dumptable(Enumhead, \"Enums\", 0);\n  printf(\"\\n\");\n  dumptable(Typehead, \"Typedefs\", 0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input032.c",
    "content": "Unknown variable or function:pizza on line 4 of input032.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input042.c",
    "content": "Unknown variable or function:fred on line 3 of input042.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input043.c",
    "content": "Unknown variable or function:b on line 3 of input043.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input044.c",
    "content": "Unknown variable or function:z on line 3 of input044.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input059.c",
    "content": "Unknown variable or function:y on line 3 of input059.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input060.c",
    "content": "Expression is not a struct/union on line 3 of input060.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input061.c",
    "content": "Expression is not a pointer to a struct/union on line 3 of input061.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input093.c",
    "content": "Unknown variable or function:fred on line 1 of input093.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input124.c",
    "content": "Cannot ++ on rvalue on line 6 of input124.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input126.c",
    "content": "Unknown variable or function:ptr on line 7 of input126.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input129.c",
    "content": "Cannot ++ and/or -- more than once on line 6 of input129.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/err.input136.c",
    "content": "Must return a value from a non-void function on line 4 of input136.c\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input122.c",
    "content": "#include <stdio.h>\n\nint x, y, z1, z2;\n\nint main() {\n  for (x= 0; x <= 1; x++) {\n    for (y= 0; y <= 1; y++) {\n      z1= x || y; z2= x && y;\n      printf(\"x %d, y %d, x || y %d, x && y %d\\n\", x, y, z1, z2);\n    }\n  }\n  \n  //z= x || y;\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input123.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  for (x=0; x < 20; x++)\n    switch(x) {\n      case 2:\n      case 3:\n      case 5:\n      case 7:\n      case 11: printf(\"%2d infant prime\\n\", x); break;\n      case 13:\n      case 17:\n      case 19: printf(\"%2d teen   prime\\n\", x); break;\n      case 0:\n      case 1:\n      case 4:\n      case 6:\n      case 8:\n      case 9:\n      case 10:\n      case 12: printf(\"%2d infant composite\\n\", x); break;\n      default: printf(\"%2d teen   composite\\n\", x); break;\n    }\n\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input124.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary++;\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input125.c",
    "content": "#include <stdio.h>\n\nint ary[5];\nint *ptr;\nint x;\n\nint main() {\n  ary[3]= 2008;\n  ptr= ary;\t\t\t// Load ary's address into ptr\n  x= ary[3]; printf(\"%d\\n\", x);\n  x= ptr[3]; printf(\"%d\\n\", x); // Treat ptr as an array\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input126.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary[3]= 2008;\n  ptr= &ary;\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input127.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nvoid fred(int *ptr) {\t\t// Receive a pointer\n  printf(\"%d\\n\", ptr[3]);\n}\n\nint main() {\n  ary[3]= 2008;\n  printf(\"%d\\n\", ary[3]);\n  fred(ary);\t\t\t// Pass ary as a pointer\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input128.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int val;\n  struct foo *next;\n};\n\nstruct foo head, mid, tail;\n\nint main() {\n  struct foo *ptr;\n  tail.val= 20; tail.next= NULL;\n  mid.val= 15; mid.next= &tail;\n  head.val= 10; head.next= &mid;\n\n  ptr= &head;\n  printf(\"%d %d\\n\", head.val, ptr->val);\n  printf(\"%d %d\\n\", mid.val, ptr->next->val);\n  printf(\"%d %d\\n\", tail.val, ptr->next->next->val);\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input129.c",
    "content": "#include <stdio.h>\n\nint x= 6;\n\nint main() {\n  printf(\"%d\\n\", x++ ++);\n  return(0);\n}\n\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input130.c",
    "content": "#include <stdio.h>\n\nchar *x= \"foo\";\n\nint main() {\n  printf(\"Hello \" \"world\" \"\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input131.c",
    "content": "#include <stdio.h>\n\nvoid donothing() { }\n\nint main() {\n  int x=0;\n  printf(\"Doing nothing... \"); donothing();\n  printf(\"nothing done\\n\");\n\n  while (++x < 100) ;\n  printf(\"x is now %d\\n\", x);\n\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input132.c",
    "content": "extern int fred;\nint fred;\n\nint mary;\nextern int mary;\n\nint main() { return(0); }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input133.c",
    "content": "#include <stdio.h>\n\nextern int fred[];\nint fred[23];\n\nchar mary[100];\nextern char mary[];\n\nvoid main() { printf(\"OK\\n\"); }\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input134.c",
    "content": "#include <stdio.h>\n\nchar y = 'a';\nchar *x;\n\nint main() {\n  x= &y;        if (x && y == 'a') printf(\"1st match\\n\");\n  x= NULL;      if (x && y == 'a') printf(\"2nd match\\n\");\n  x= &y; y='b'; if (x && y == 'a') printf(\"3rd match\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input135.c",
    "content": "#include <stdio.h>\n\nvoid fred() {\n  int x= 5;\n  printf(\"testing x\\n\");\n  if (x > 4) return;\n  printf(\"x below 5\\n\");\n}\n\nint main() {\n  fred();\n  return(0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/input136.c",
    "content": "#include <stdio.h>\n\nint main() {\n  return;\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input122.c",
    "content": "x 0, y 0, x || y 0, x && y 0\nx 0, y 1, x || y 1, x && y 0\nx 1, y 0, x || y 1, x && y 0\nx 1, y 1, x || y 1, x && y 1\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input123.c",
    "content": " 0 infant composite\n 1 infant composite\n 2 infant prime\n 3 infant prime\n 4 infant composite\n 5 infant prime\n 6 infant composite\n 7 infant prime\n 8 infant composite\n 9 infant composite\n10 infant composite\n11 infant prime\n12 infant composite\n13 teen   prime\n14 teen   composite\n15 teen   composite\n16 teen   composite\n17 teen   prime\n18 teen   composite\n19 teen   prime\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input125.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input127.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input128.c",
    "content": "10 10\n15 15\n20 20\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input130.c",
    "content": "Hello world\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input131.c",
    "content": "Doing nothing... nothing done\nx is now 100\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input132.c",
    "content": ""
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input133.c",
    "content": "OK\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input134.c",
    "content": "1st match\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/out.input135.c",
    "content": "testing x\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "53_Mop_up_pt2/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "53_Mop_up_pt2/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->ctype = ctype;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n  int i;\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    case A_TOBOOL:\n      fprintf(stdout, \"A_TOBOOL\\n\");\n      return;\n    case A_LOGOR:\n      fprintf(stdout, \"A_LOGOR\\n\");\n      return;\n    case A_LOGAND:\n      fprintf(stdout, \"A_LOGAND\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "53_Mop_up_pt2/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n\t\t\t    struct symtable *rctype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // For A_LOGOR and A_LOGAND, both types have to be int or pointer types\n  if (op==A_LOGOR || op==A_LOGAND) {\n    if (!inttype(ltype) && !ptrtype(ltype))\n      return(NULL);\n    if (!inttype(ltype) && !ptrtype(rtype))\n      return(NULL);\n    return (tree);\n  }\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, NULL, tree, NULL, 0));\n  }\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return (tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, rctype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "54_Reg_Spills/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "54_Reg_Spills/Readme.md",
    "content": "# Part 54: Spilling Registers\n\nI've been putting off dealing with\n[register spilling](https://en.wikipedia.org/wiki/Register_allocation#Spilling)\nfor a while because I knew the issue was going to be thorny. I think what I've\ndone here is a first cut at the problem. It's naive, but it is a start.\n\n## The Issues\n\nRegisters are a limited commodity in most CPUs. They are the fastest\nstorage units, and we use them to hold temporary results while we\nevaluate expressions. Once we have stored a result into a more permanent\nlocation (e.g. a memory location which represents a variable) we can\nfree the in-use registers and re-use them.\n\nOnce we hit expressions of large complexity we run out of enough registers\nto hold the intermediate results, and this prevents us from evaluating the\nexpression.\n\nAt present the compiler can allocate up to four registers. Yes, I know this\nis a bit artificial; however, there will always be an expression so complex\nthat it can't be evaluated with a fixed number of registers.\n\nConsider this expression, and remember the order of precedence of the C\noperators:\n\n```c\n  int x= 5 || 6 && 7 | 8 & 9 << 2 + 3 * 4;\n```\n\nEach operator on the right has higher precedence that the one on its left.\nThus, we need to store 5 into a register, but then evaluate the rest of the\nexpression. Now we store 6 into a register, and ditto. Now, 7 in a register\nand ditto. Now 8 in a register and ditto.\n\nOops! We now need to load 9 into a register, but all four registers are\nallocated. In fact, we'll need to allocate another *four* registers to\nevaluate this expression. What is the solution?\n\nThe solution is to \n[spill registers](https://en.wikipedia.org/wiki/Register_allocation#Spilling)\nsomewhere in main memory so that we free up a register. However, we also need\nto reload the spilled register at the point when we need it; this means\nthat it must now be free to have its old value reloaded.\n\nSo, we need not only the ability to spill registers somewhere but also\ntrack which ones were spilled and when, and reload them as needed. It's\ntricky. You can see by the external link above that there is a tonne of\ntheory behind optimal register allocation and spilling. This isn't going to\nbe the place for that theory. I'll implement a simple solution and leave\nyou the opportunity to improve the code based on the theory!\n\nNow, where do registers get spilled? We could allocate an arbitrary sized\n[memory heap](https://en.wikipedia.org/wiki/Memory_management#Dynamic_memory_allocation) and store all the spilled registers here. Generally, though, most\nregister spill implementations use the existing stack. Why?\n\nThe answers are that we already have hardware-defined *push* and *pop*\noperations on the stack which are quick. We can (usually) rely on the\noperating system extending the stack size indefinitely. Also, we divide our\nstack up into stack frames, one per function. At the end of a function we\ncan simply move the stack pointer, and we don't have to worry about popping\noff any registers that we spilled and somehow forgot about.\n\nI'm going to use the stack for spilling registers in our compiler. \nLet's look at the implications of spilling and of using the stack.\n\n## The Implications\n\nTo do register spilling, we need the ability to:\n\n + Choose and spill one register's value when we need to allocate a register\n   and none are free. It will be pushed on to the stack.\n + Reload the spilled register's value fron the stack when we need it.\n + Ensure that the register is free at the point when we need to reload\n   its value.\n + Before a function call, we need to spill all in-use registers. This is\n   because a function call is an expression. We need to be able to do\n   `2 + 3 * fred(4,5) - 7`, and still have the 2 and 3 in registers once\n   the function returns with its value.\n + Thus, we need to reload all the registers that we spilled before a\n   function call.\n\nThe above is what we need, regardless of the mechanism. Now let's bring\nthe stack in and see how it will constrain us.\n\nIf we can only push a register's value on the stack to spill it, and pop a\nregister's value from the stack, this implies that we have to reload\nregisters in the reverse order in which we spilled them on the stack.\nIs this something that we can guarantee? In other words, will we ever need\nto reload a register out of order? If so, the stack isn't going to be\nthe mechanism that we need. Alternatively, can we write our compiler\nto ensure that the registers reload in reverse spill order?\n\n## Some Optimisations\n\nIf you have read the external link above, or you know something about\nregister allocation already, then you know there are so many ways we\ncan optimise register allocation and spilling. You probably know much\nmore than I do, so don't giggle too much in the next section.\n\nWhen we call a function, not all of our registers will be allocated\nalready. Also, some registers will be used to hold some of the\nargument values for the function. Also, the function will likely\nreturn a value and hence destroy a register. Thus, we don't have to\nspill all of our registers onto the stack before we do a function call.\nIf we were clever, we could work out which registers have to be spilled\nand only spill these ones.\n\nWe can even take a step back and rewrite the AST tree to ease the pressure\non our expression evaluation. For example, we could use a form of\n[strength reduction](https://en.wikipedia.org/wiki/Strength_reduction)\nto lower the number of registers allocated.\n\nConsider the expression:\n\n```c\n  2 + (3 + (4 + (5 + (6 + (7 + 8)))))\n```\n\nThe way it is written, we would have to load 2 into a register, start to\nevaluate the rest, load 3 into a register and ditto. We would end up with\nseven register allocations.\n\nHowever, addition is *commutative*, and therefore we can re-visualise the above\nexpression as:\n\n```c\n  ((((2 + 3) + 4) + 5) + 6) + 7\n```\n\nNow we can evaluate `2+3` and put it into a register, add on `4` and still\nonly need one register, etc. This is something that the\n[SubC](http://www.t3x.org/subc/) compiler does with its AST trees, and it\nis something that I'll implement later.\n\nBut for now, no optimisations. In fact, the spilling code is going to\nproduce some pretty bad assembly. But at least the assembly that it\nproduces works. Remember, \"*premature optimisation is the root of all\nevil*\" -- Donald Knuth.\n\n## The Nuts and Bolts\n\nLet's start with the most primitive new functions in `cg.c`:\n\n```c\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpopq\\t%s\\n\", reglist[r]);\n}\n```\n\nWe can use these to spill and reload a register on the stack. Note that I\ndidn't call them `spillreg()` and `reloadreg()`. They are general-purpose\nand we might use them for something else later.\n\n## The `spillreg`\n\nNext up is a new static variable in `cg.c`:\n\n```c\nstatic int spillreg=0;\n```\n\nThis is the next register that we will choose to spill on the stack. Each\ntime we spill a register, we will increment `spillreg`. So it eventually\nwill be 4, then 5, ... then 8, ... then 3002 etc.\n\nQuestion: why not reset it to zero when we got past the maximum number of\nregisters? The answer is that, when we pop registers from the stack, we\nneed to know when to *stop* popping registers. If we had used modulo\narithmetic, we would pop in a fixed cycle and not know when to stop.\n\nThat said, we must only spill registers from 0 to `NUMFREEREGS-1`, so we\nwill do some modulo arithmetic in the following code.\n\n## Spilling One Register\n\nWe spill a register when there are no free registers. We will choose\nthe `spillreg` (modulo NUMFREEREGS) register to spill. In the \n`alloc_register()` function in `cg.c`:\n\n```c\nint alloc_register(void) {\n  int reg;\n\n  // Try to allocate a register but fail\n  ...\n  // We have no registers, so we must spill one\n  reg= (spillreg % NUMFREEREGS);\n  spillreg++;\n  fprintf(Outfile, \"# spilling reg %d\\n\", reg);\n  pushreg(reg);\n  return (reg);\n}\n```\n\nWe choose `spillreg % NUMFREEREGS` as the register to spill, and we\n`pushreg(reg)` to do so. We increment `spillreg` to be the next register to\nspill, and we return the newly spilled register number as that is now free.\nI also have a debug statement in there which I'll remove later.\n\n## Reloading One Register\n\nWe can only reload a register when a) it becomes free and b) its the\nmost recent register that was spilled onto the stack. Here is where\nwe insert an implicit assumption into our code: we must always reload\nthe most recently-spilled register. We had better make sure that the\ncompiler can keep this promise.\n\nThe new code in `free_register()` in `cg.c` is:\n\n```c\nstatic void free_register(int reg) {\n  ...\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg= (spillreg % NUMFREEREGS);\n    fprintf(Outfile, \"# unspilling reg %d\\n\", reg);\n    popreg(reg);\n  } else        // Simply free the in-use register\n  ...\n}\n```\n\nWe simply undo the most recent spill, and decrement `spillreg`. Note that\nthis is why we didn't store `spillreg` with a modulo value. Once it hits\nzero, we know that there are no spilled registers on the stack and there\nis no point in trying to pop a register value from the stack.\n\n## Register Spills Before a Function Call\n\nAs I mentioned before, a clever compiler would determine which registers\n*had* to be spilled before a function call. This is not a clever\ncompiler, and so we have these new functions:\n\n```c\n// Spill all registers on the stack\nvoid spill_all_regs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void unspill_all_regs(void) {\n  int i;\n\n  for (i = NUMFREEREGS-1; i >= 0; i--)\n    popreg(i);\n}\n```\n\nAt this point, while you are either laughing or crying (or both), I'll\nremind you of a Ken Thompson quote: \"*When in doubt, use brute force.*\"\n\n## Keeping Our Assumptions Intact\n\nWe have an implicit assumption built into this code: any reloaded register\nwas the one last spilled. We had better check that this is the case.\n\nFor binary expressions, `genAST()` in `gen.c` does this:\n\n```c\n  // Get the left and right sub-tree values\n  leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    // Do the specific binary operation\n  }\n```\n\nWe allocate the register for the left-hand expression first, then the\nregister for the right-hand expression. If we have to spill\nregisters, then the register for the right-hand expression will be the most\nrecently-spilled register.\n\nTherefore, we had better *free* the register for the right-hand expression\nfirst, to ensure that any spilled value will get reloaded back into this\nregister.\n\nI've gone through `cg.c` and made some modifications to the binary\nexpression generators to do this. An example is `cgadd()` in `cg.c`:\n\n```c\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n```\n\nThe code used to add into `r2`, free `r1` and return `r2`. Not good, but\nluckily addition is commutative. We can save the result in either register,\nso now `r1` returns the result and `r2` is freed. If if was spilled, it\nwill get its old value back.\n\nI *hope* that I've done this everywhere that is needed, and I *hope*\nthat our assumption is not satisfied, but I'm not completely sure yet.\nWe will have to do a lot of testing to be reasonably satisfied.\n\n## Changes to Function Calls\n\nWe now have the spill/reload nuts and bolts in place. For ordinary\nregister allocations and frees, the above code will spill and reload\nas required. We also try to ensure that we free the most recently\nspilled register.\n\nThe last thing we need to do is spill the registers before a function call\nand reload them afterwards. There is a wrinkle: the function may be part of\nan expression. We need to:\n\n  1. Spill the registers first.\n  1. Copy the arguments to the function (using the registers).\n  1. Call the function.\n  1. Reload the registers before we\n  1. Copy the register's return value.\n\nIf we do the last two out of order, we will lose the returned value\nas we reload all the old registers.\n\nTo make the above happen, I've had to share the spill/reload duties\nbetween `gen.c` and `cg.c` as follows.\n\nIn `gen_funccall()` in `gen.c`:\n\n```c\nstatic int gen_funccall(struct ASTnode *n) {\n  ...\n\n  // Save the registers before we copy the arguments\n  spill_all_regs();\n\n  // Walk the list of arguments and copy them\n  ...\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n```\n\nwhich does steps 1, 2 and 3: spill, copy, call. And in `cgcall()` in `cg.c`:\n\n```c\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  ...\n  // Remove any arguments pushed on the stack\n  ...\n\n  // Unspill all the registers\n  unspill_all_regs();\n\n  // Get a new register and copy the return value into it\n  outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n```\n\nwhich does the final two steps: reload and copy the return value.\n\n## Example Time\n\nHere are some examples which cause register spills: function calls and\ncomplex expressions. We'll start with `tests/input136.c`:\n\n```c\nint add(int x, int y) {\n  return(x+y);\n}\n\nint main() {\n  int result;\n  result= 3 * add(2,3) - 5 * add(4,6);\n  printf(\"%d\\n\", result);\n  return(0);\n}\n```\n\n`add()` needs to be treated as an expression. We put 3 into a register,\nand spill all the registers before we call `add(2,3)`. We reload the\nregisters before we get the return value. The assembly code is:\n\n```\n        movq    $3, %r10        # Get 3 into %r10\n        pushq   %r10\n        pushq   %r11            # Spill all four registers, thus\n        pushq   %r12            # preserving the %r10 value\n        pushq   %r13\n        movq    $3, %r11        # Copy the 3 and 2 arguments\n        movq    %r11, %rsi\n        movq    $2, %r11\n        movq    %r11, %rdi\n        call    add@PLT         # Call add()\n        popq    %r13\n        popq    %r12            # Reload all four registers, thus\n        popq    %r11            # restoring the %r10 value\n        popq    %r10\n        movq    %rax, %r11      # Get the return value into %r11\n        imulq   %r11, %r10      # Multiply 3 * add(2,3)\n```\n\nYes, there is plenty of scope for optimisation here. KISS, though.\n\nIn `tests/input137.c`, there is this expression:\n\n```c\n  x= a + (b + (c + (d + (e + (f + (g + h))))));\n```\n\nwhich requires eight registers and so we'll need to spill four of them. The\ngenerated assembly code is:\n\n```\n        movslq  a(%rip), %r10\n        movslq  b(%rip), %r11\n        movslq  c(%rip), %r12\n        movslq  d(%rip), %r13\n        pushq   %r10             # spilling %r10\n        movslq  e(%rip), %r10\n        pushq   %r11             # spilling %r11\n        movslq  f(%rip), %r11\n        pushq   %r12             # spilling %r12\n        movslq  g(%rip), %r12\n        pushq   %r13             # spilling %r13\n        movslq  h(%rip), %r13\n        addq    %r13, %r12\n        popq    %r13            # unspilling %r13\n        addq    %r12, %r11\n        popq    %r12            # unspilling %r12\n        addq    %r11, %r10\n        popq    %r11            # unspilling %r11\n        addq    %r10, %r13\n        popq    %r10            # unspilling %r10\n        addq    %r13, %r12\n        addq    %r12, %r11\n        addq    %r11, %r10\n        movl    %r10d, -4(%rbp)\n```\n\nand overall we end up with the correct expression evaluation.\n\n## Conclusion and What's Next\n\nRegister allocating and spilling is hard to get right, and there is a\nlot of optimisation theory which can be brought to bear. I've implemented\nquite a naive approach to register  allocating and spilling. It will work\nbut there is substantial room for improvement.\n\nWhile doing the above, I also fixed the problem with `&&` and `||`. I've\ndecided to write these changes up in the next part, even though the\ncode here already has these changes. [Next step](../55_Lazy_Evaluation/Readme.md)\n"
  },
  {
    "path": "54_Reg_Spills/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n\tfatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpopq\\t%s\\n\", reglist[r]);\n}\n\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg=0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      return (reg);\n    }\n  }\n\n  // We have no registers, so we must spill one\n  reg= (spillreg % NUMFREEREGS);\n  spillreg++;\n  fprintf(Outfile, \"# spilling reg %d\\n\", reg);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0) {\n    fprintf(Outfile, \"# error trying to free register %d\\n\", reg);\n    fatald(\"Error trying to free register\", reg);\n  }\n\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg= (spillreg % NUMFREEREGS);\n    fprintf(Outfile, \"# unspilling reg %d\\n\", reg);\n    popreg(reg);\n  } else {\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid spill_all_regs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void unspill_all_regs(void) {\n  int i;\n\n  for (i = NUMFREEREGS-1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\" \"\\t.type\\t%s, @function\\n\", name, name);\n  fprintf(Outfile, \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\" \"\\tmovq\\t%%rsp, %%rbp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n  freeall_registers(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn,\n\t\treglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn,\n\t\treglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", val, reglist[r]);\n}\n\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch(op) {\n    case A_IF:\n    case A_WHILE:\n    case A_LOGAND:\n      fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n      break;\n    case A_LOGOR:\n      fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n      break;\n    default:\n      fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n      fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n\n  // Unspill all the registers\n  unspill_all_regs();\n\n  // Get a new register and copy the return value into it\n  outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n  free_register(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r],\n\t\tsym->st_posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r],\n\t\tsym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n      case 1:\n\tfprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n\tbreak;\n      case 8:\n\t// Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n\tif (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t    && initvalue != 0)\n\t  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n\telse\n\t  fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n\tbreak;\n      default:\n\tfor (i = 0; i < size; i++)\n\t  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n        case P_CHAR:\n\t  fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n\t  break;\n        case P_INT:\n\t  fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n\t  break;\n        case P_LONG:\n\t  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n\t  break;\n        default:\n\t  fatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n}\n"
  },
  {
    "path": "54_Reg_Spills/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "54_Reg_Spills/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int type) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (cgprimsize(type) > 4) ? cgprimsize(type) : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpop\\t%s\\n\", reglist[r]);\n}\n\n// Set all registers as available\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg=0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      return (reg);\n    }\n  }\n  // We have no registers, so we must spill one\n  reg = (spillreg % NUMFREEREGS);\n  spillreg++;\n  fprintf(Outfile, \"; spilling reg %d\\n\", reg);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0) {\n    fprintf(Outfile, \"# error trying to free register %d\\n\", reg);\n    fatald(\"Error trying to free register\", reg);\n  }\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg= (spillreg % NUMFREEREGS);\n    fprintf(Outfile, \"; unspilling reg %d\\n\", reg);\n    popreg(reg);\n  } else {\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid spill_all_regs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void unspill_all_regs(void) {\n  int i;\n\n  for (i = NUMFREEREGS-1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", name);\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->type);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->type);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n  freeall_registers(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], val);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch(op) {\n    case A_IF:\n    case A_WHILE:\n    case A_LOGAND:\n      fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n      break;\n    case A_LOGOR:\n      fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n      break;\n    default:\n      fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // Unspill all the registers\n  unspill_all_regs();\n  // Get a new register and copy the return value into it\n  outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n  free_register(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n        case P_CHAR:\n          fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n          break;\n        case P_INT:\n          fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n          break;\n        case P_LONG:\n          fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n          break;\n        default:\n          fatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 2:\n    case 4:\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n}\n"
  },
  {
    "path": "54_Reg_Spills/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Linestart;\t\t     \t// True if at start of a line\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\nextern char *Tstring[];\t\t\t// List of token strings\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_dumpsym;\t\t// If true, dump the symbol table\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "54_Reg_Spills/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Get the type inside the parentheses\n  type = parse_stars(parse_type(ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return (type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree = optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type = tree->type;\n    tree = tree->left;\n  }\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return (tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue == 0)\n      return (0);\n  }\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return (tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a pointer to a symbol that may already exist\n// return true if this symbol doesn't exist. We use\n// this function to convert externs into globals\nint is_new_symbol(struct symtable *sym, int class, \n\t\t  int type, struct symtable *ctype) {\n\n  // There is no existing symbol, thus is new\n  if (sym==NULL) return(1);\n\n  // global versus extern: if they match that it's not new\n  // and we can convert the class to global\n  if ((sym->class== C_GLOBAL && class== C_EXTERN)\n      || (sym->class== C_EXTERN && class== C_GLOBAL)) {\n\n      // If the types don't match, there's a problem\n      if (type != sym->type)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // Struct/unions, also compare the ctype\n      if (type >= P_STRUCT && ctype != sym->ctype)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // If we get to here, the types match, so mark the symbol\n      // as global\n      sym->class= C_GLOBAL;\n      // Return that symbol is not new\n      return(0);\n  }\n\n  // It must be a duplicate symbol if we get here\n  fatals(\"Duplicate global variable declaration\", sym->name);\n  return(-1);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree = NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, type, ctype))\n        sym = addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym = addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym = addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist = (int *) malloc(sizeof(int));\n      sym->initlist[0] = parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym->ctype, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, varnode->ctype, 0);\n      if (exprnode == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode->ctype, exprnode,\n\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t\t// New symbol table entry\n  int nelems = -1;\t\t// Assume the number of elements won't be given\n  int maxelems;\t\t\t// The maximum number of elements in the init list\n  int *initlist;\t\t// The list of initial elements \n  int i = 0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems = parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, pointer_to(type), ctype))\n        sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class, 0, 0);\n      break;\n    default:\n      fatal(\"For now, declaration of non-global arrays is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems = nelems;\n    else\n      maxelems = TABLE_INCREMENT;\n    initlist = (int *) malloc(maxelems * sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n\tfatal(\"Too many values in initialisation list\");\n\n      initlist[i++] = parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n\tmaxelems += TABLE_INCREMENT;\n\tinitlist = (int *) realloc(initlist, maxelems * sizeof(int));\n      }\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n\tscan(&Token);\n\tbreak;\n      }\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j = i; j < sym->nelems; j++)\n      initlist[j] = 0;\n    if (i > nelems)\n      nelems = i;\n    sym->initlist = initlist;\n  }\n  // Set the size of the array and the number of elements\n  sym->nelems = nelems;\n  sym->size = sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n\tparamcnt = 0;\n\tscan(&Token);\n\tbreak;\n      }\n    }\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, ctype, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree = optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t = declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t == -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead == NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name = NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET)\n    sym = array_declaration(varname, type, ctype, class);\n  else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree = NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n\tfatal(\"Function definition not at global level\");\n      return (type);\n    }\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree == NULL)\n      *gluetree = tree;\n    else\n      *gluetree =\n\tmkastnode(A_GLUE, P_NONE, NULL, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n  return(0);\t// Keep -Wall happy\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype= NULL;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "54_Reg_Spills/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int level);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue, int append);\nvoid genglobstrend(void);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nint alloc_register(void);\nvoid freeall_registers(int keepreg);\nvoid spill_all_regs(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue, int append);\nvoid cgglobstrend(void);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nvoid cgloadboolean(int r, int val);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\nvoid dumptable(struct symtable *head, char *name, int indent);\nvoid dumpsymtables(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(struct symtable **ctype);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n                            struct symtable *rctype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "54_Reg_Spills/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -w-ptr -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_QUESTION, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\t// 1\n  A_TERNARY, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\t\t// 6\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\t// 12\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\t\t\t// 20\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\t\t\t\t// 24\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\t\t\t// 28\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\t\t\t\t// 33\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\t\t\t// 37\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\t\t// 41\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\t\t// 46\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "54_Reg_Spills/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree =\n      mkastnode(A_GLUE, P_NONE, NULL, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree =\n    mkastunary(A_FUNCCALL, funcptr->type, funcptr->ctype, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(struct ASTnode *left) {\n  struct ASTnode *right;\n\n  // Check that the sub-tree is a pointer\n  if (!ptrtype(left->type))\n    fatal(\"Not an array or pointer\");\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, left->ctype, A_ADD);\n\n  // Return an AST tree where the array's base has the offset added to it,\n  // and dereference the element. Still an lvalue at this point.\n  left =\n    mkastnode(A_ADD, left->type, left->ctype, left, NULL, right, NULL, 0);\n  left =\n    mkastunary(A_DEREF, value_at(left->type), left->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(struct ASTnode *left, int withpointer) {\n  struct ASTnode *right;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the left AST tree is a pointer to struct or union\n  if (withpointer && left->type != pointer_to(P_STRUCT)\n      && left->type != pointer_to(P_UNION))\n    fatal(\"Expression is not a pointer to a struct/union\");\n\n  // Or, check that the left AST tree is a struct or union.\n  // If so, change it from an A_IDENT to an A_ADDR so that\n  // we get the base address, not the value at this address.\n  if (!withpointer) {\n    if (left->type == P_STRUCT || left->type == P_UNION)\n      left->op = A_ADDR;\n    else\n      fatal(\"Expression is not a struct/union\");\n  }\n\n  // Get the details of the composite type\n  typeptr = left->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left =\n    mkastnode(A_ADD, pointer_to(m->type), m->ctype, left, NULL, right, NULL,\n\t      0);\n  left = mkastunary(A_DEREF, m->type, m->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse a parenthesised expression and\n// return an AST node representing it.\nstatic struct ASTnode *paren_expression(void) {\n  struct ASTnode *n;\n  int type = 0;\n  struct symtable *ctype = NULL;\n\n  // Beginning of a parenthesised expression, skip the '('.\n  scan(&Token);\n\n  // If the token after is a type identifier, this is a cast expression\n  switch (Token.token) {\n  case T_IDENT:\n    // We have to see if the identifier matches a typedef.\n    // If not, treat it as an expression.\n    if (findtypedef(Text) == NULL) {\n      n = binexpr(0);\n      break;\n    }\n  case T_VOID:\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n  case T_STRUCT:\n  case T_UNION:\n  case T_ENUM:\n    // Get the type inside the parentheses\n    type = parse_cast(&ctype);\n\n    // Skip the closing ')' and then parse the following expression\n    rparen();\n\n  default:\n    n = binexpr(0);\t\t// Scan in the expression\n  }\n\n  // We now have at least an expression in n, and possibly a non-zero type\n  // in type if there was a cast. Skip the closing ')' if there was no cast.\n  if (type == 0)\n    rparen();\n  else\n    // Otherwise, make a unary AST node for the cast\n    n = mkastunary(A_CAST, type, ctype, n, NULL, 0);\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  struct symtable *enumptr;\n  struct symtable *varptr;\n  int id;\n  int type = 0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type = parse_stars(parse_type(&ctype, &class));\n\n    // Get the type's size\n    size = typesize(type, ctype);\n    rparen();\n\n    // Make a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    id = genglobstr(Text, 0);\n\n    // For successive STRLIT tokens, append their contents\n    // to this one\n    while (1) {\n      scan(&Peektoken);\n      if (Peektoken.token != T_STRLIT) break;\n      genglobstr(Text, 1);\n      scan(&Token);\t// To skip it properly\n    }\n\n    // Now make a leaf AST node for it. id is the string's label.\n    genglobstrend();\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, NULL, id);\n    break;\n\n  case T_IDENT:\n    // If the identifier matches an enum value,\n    // return an A_INTLIT node\n    if ((enumptr = findenumval(Text)) != NULL) {\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, enumptr->st_posn);\n      break;\n    }\n    // See if this identifier exists as a symbol. For arrays, set rvalue to 1.\n    if ((varptr = findsymbol(Text)) == NULL)\n      fatals(\"Unknown variable or function\", Text);\n    switch (varptr->stype) {\n    case S_VARIABLE:\n      n = mkastleaf(A_IDENT, varptr->type, varptr->ctype, varptr, 0);\n      break;\n    case S_ARRAY:\n      n = mkastleaf(A_ADDR, varptr->type, varptr->ctype, varptr, 0);\n      n->rvalue = 1;\n      break;\n    case S_FUNCTION:\n      // Function call, see if the next token is a left parenthesis\n      scan(&Token);\n      if (Token.token != T_LPAREN)\n\tfatals(\"Function name used without parentheses\", Text);\n      return (funccall());\n    default:\n      fatals(\"Identifier not a scalar or array variable\", Text);\n    }\n    break;\n\n  case T_LPAREN:\n    return (paren_expression());\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n\n  // Get the primary expression\n  n = primary();\n\n  // Loop until there are no more postfix operators\n  while (1) {\n    switch (Token.token) {\n    case T_LBRACKET:\n      // An array reference\n      n = array_access(n);\n      break;\n\n    case T_DOT:\n      // Access into a struct or union\n      n = member_access(n, 0);\n      break;\n\n    case T_ARROW:\n      // Pointer access into a struct or union\n      n = member_access(n, 1);\n      break;\n\n    case T_INC:\n      // Post-increment: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot ++ on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTINC;\n      break;\n\n    case T_DEC:\n      // Post-decrement: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot -- on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTDEC;\n      break;\n\n    default:\n      return (n);\n    }\n  }\n\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatals(\"Token with no precedence in op_precedence:\", Tstring[tokentype]);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (prec);\n}\n\n// prefix_expression: postfix_expression\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Prevent '&' being performed on an array\n    if (tree->sym->stype == S_ARRAY)\n      fatal(\"& operator cannot be performed on an array\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree =\n      mkastunary(A_DEREF, value_at(tree->type), tree->ctype, tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this if needed to int so that it's signed\n    tree->rvalue = 1;\n    if (tree->type == P_CHAR)\n      tree->type = P_INT;\n    tree = mkastunary(A_NEGATE, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  default:\n    tree = postfix();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp = binexpr(0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. XXX We should also\n      // consider the third expression's type.\n      return (mkastnode\n\t      (A_TERNARY, right->type, right->ctype, left, right, ltemp,\n\t       NULL, 0));\n\n    case A_ASSIGN:\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, left->ctype, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n      break;\n\n    default:\n      // We are not doing a ternary or assignment, so both trees should\n      // be rvalues. Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, right->ctype, ASTop);\n      rtemp = modify_type(right, left->type, left->ctype, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left->ctype, left, NULL,\n\t\tright, NULL, 0);\n\n    // Some operators produce an int result regardless of their operands\n    switch (binastop(tokentype)) {\n    case A_LOGOR:\n    case A_LOGAND:\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      left->type = P_INT;\n    }\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "54_Reg_Spills/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs(reg);\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    if (c->left)\n      genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs(NOREG);\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for an\n// A_LOGAND or A_LOGOR operation\nstatic int gen_logandor(struct ASTnode *n) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n  int reg;\n\n  // Generate the code for the left expression\n  // followed by the jump to the false label\n  reg= genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(NOREG);\n\n  // Generate the code for the right expression\n  // followed by the jump to the false label\n  reg= genAST(n->right, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(reg);\n\n  // We didn't jump so set the right boolean value\n  if (n->op== A_LOGAND) {\n    cgloadboolean(reg, 1);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 0);\n  } else {\n    cgloadboolean(reg, 0);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 1);\n  }\n  cglabel(Lend);\n  return(reg);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // Save the registers before we copy the arguments\n  spill_all_regs();\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg= NOREG, rightreg= NOREG;\n\n  // Empty tree, do nothing\n  if (n==NULL) return(NOREG);\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_TERNARY:\n      return (gen_ternary(n));\n    case A_LOGOR:\n      return (gen_logandor(n));\n    case A_LOGAND:\n      return (gen_logandor(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL)\n\tgenAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs(NOREG);\n      if (n->right != NULL)\n\tgenAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs(NOREG);\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF, A_WHILE or A_TERNARY,\n      // generate a compare followed by a jump. Otherwise, compare\n      // registers and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE ||\n\t  parentASTop == A_TERNARY)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->a_intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->a_intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n\tcase A_ASPLUS:\n\t  leftreg = cgadd(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASMINUS:\n\t  leftreg = cgsub(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSTAR:\n\t  leftreg = cgmul(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSLASH:\n\t  leftreg = cgdiv(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL ||\n\t      n->right->sym->class == C_STATIC)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->a_size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL || n->left->sym->class == C_STATIC)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (leftreg);\t\t// Not much to do\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs(int keepreg) {\n  freeall_registers(keepreg);\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\n\n// Generate a global string.\n// If append is true, append to\n// previous genglobstr() call.\nint genglobstr(char *strvalue, int append) {\n  int l = genlabel();\n  cgglobstr(l, strvalue, append);\n  return (l);\n}\nvoid genglobstrend(void) {\n  cgglobstrend();\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "54_Reg_Spills/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\nint toupper(int c);\nint tolower(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "54_Reg_Spills/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "54_Reg_Spills/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "54_Reg_Spills/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "54_Reg_Spills/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n#ifndef EOF\n# define EOF (-1)\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint fgetc(FILE *stream);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "54_Reg_Spills/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "54_Reg_Spills/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\nint strcmp(char *s1, char *s2);\nint strncmp(char *s1, char *s2, size_t n);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "54_Reg_Spills/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "54_Reg_Spills/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix;\n  posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Linestart = 1;\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token = 0;\t\t// and set there is no lookahead token\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n\n  // Dump the symbol table if requested\n  if (O_dumpsym) {\n    printf(\"Symbols for %s\\n\", filename);\n    dumpsymtables();\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcSTM] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -M dump the symbol table for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_dumpsym = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'M':\n\t  O_dumpsym = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "54_Reg_Spills/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "54_Reg_Spills/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  int i;\n  for (i = 0; s[i] != '\\0'; i++)\n    if (s[i] == (char) c)\n      return (i);\n  return (-1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (Linestart && c == '#') {\t// We've hit a pre-processor statement\n    Linestart = 0;\t\t// No longer at the start of the line\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n\n  Linestart = 0;\t\t// No longer at the start of the line\n  if ('\\n' == c) {\n    Line++;\t\t\t// Increment line count\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return (n);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn (hexchar());\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = (char)c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = (char)c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "54_Reg_Spills/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, NULL, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, NULL, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, NULL, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree= NULL;\n\n  // Ensure we have 'return'\n  match(T_RETURN, \"return\");\n\n  // See if we have a return value\n  if (Token.token == T_LPAREN) {\n    // Can't return a value if function returns P_VOID\n    if (Functionid->type == P_VOID)\n      fatal(\"Can't return from a void function\");\n\n    // Skip the left parenthesis\n    lparen();\n\n    // Parse the following expression\n    tree = binexpr(0);\n\n    // Ensure this is compatible with the function's type\n    tree = modify_type(tree, Functionid->type, Functionid->ctype, 0);\n    if (tree == NULL)\n      fatal(\"Incompatible type to return\");\n\n    // Get the ')'\n    rparen();\n  }\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, NULL, tree, NULL, 0);\n\n  // Get the ';'\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, P_NONE, NULL, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, P_NONE, NULL, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *body, *n, *c;\n  struct ASTnode *casetree = NULL, *casetail;\n  int inloop = 1, casecount = 0;\n  int seendefault = 0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left = binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n = mkastunary(A_SWITCH, P_NONE, NULL, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch (Token.token) {\n\t// Leave the loop when we hit a '}'\n      case T_RBRACE:\n\tif (casecount == 0)\n\t  fatal(\"No cases in switch\");\n\tinloop = 0;\n\tbreak;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token == T_DEFAULT) {\n\t  ASTop = A_DEFAULT;\n\t  seendefault = 1;\n\t  scan(&Token);\n\t} else {\n\t  ASTop = A_CASE;\n\t  scan(&Token);\n\t  left = binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue = left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n\t  // that there isn't a duplicate case value\n\t  for (c = casetree; c != NULL; c = c->right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n\t}\n\n\t// Scan the ':' and increment the casecount\n\tmatch(T_COLON, \":\");\n\tcasecount++;\n\n\t// If the next token is a T_CASE, the existing case will fall\n\t// into the next case. Otherwise, parse the case body.\n\tif (Token.token == T_CASE)\n\t  body = NULL;\n\telse\n\t  body = compound_statement(1);\n\n\t// Build a sub-tree with any compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree == NULL) {\n\t  casetree = casetail =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t} else {\n\t  casetail->right =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t  casetail = casetail->right;\n\t}\n\tbreak;\n      default:\n\tfatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue = casecount;\n  n->right = casetree;\n  rbrace();\n\n  return (n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_SEMI:\n      // An empty statement\n      semi();\n      break;\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return (stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt = binexpr(0);\n\tsemi();\n\treturn (stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt = binexpr(0);\n      semi();\n      return (stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Leave if we've hit the end token. We do this first to allow\n    // an empty compound statement\n    if (Token.token == T_RBRACE)\n      return (left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT))\n      return (left);\n\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, NULL, left, NULL, tree, NULL, 0);\n    }\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n"
  },
  {
    "path": "54_Reg_Spills/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list,\n\t\t\t\t      int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class == 0 || class == list->class)\n\treturn (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead = Globtail = NULL;\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Membhead = Membtail = NULL;\n  Structhead = Structtail = NULL;\n  Unionhead = Uniontail = NULL;\n  Enumhead = Enumtail = NULL;\n  Typehead = Typetail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev = NULL;\n\n  // Walk the global table looking for static entries\n  for (g = Globhead; g != NULL; g = g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL)\n\tprev->next = g->next;\n      else\n\tGlobhead->next = g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n\tif (prev != NULL)\n\t  Globtail = prev;\n\telse\n\t  Globtail = Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev = g;\n}\n\n// Dump a single symbol\nstatic void dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n    case P_VOID:\n      printf(\"void \");\n      break;\n    case P_CHAR:\n      printf(\"char \");\n      break;\n    case P_INT:\n      printf(\"int \");\n      break;\n    case P_LONG:\n      printf(\"long \");\n      break;\n    case P_STRUCT:\n      if (sym->ctype != NULL)\n\tprintf(\"struct %s \", sym->ctype->name);\n      else\n\tprintf(\"struct %s \", sym->name);\n      break;\n    case P_UNION:\n      if (sym->ctype != NULL)\n\tprintf(\"union %s \", sym->ctype->name);\n      else\n\tprintf(\"union %s \", sym->name);\n      break;\n    default:\n      printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++)\n    printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      break;\n    case S_FUNCTION:\n      printf(\"()\");\n      break;\n    case S_ARRAY:\n      printf(\"[]\");\n      break;\n    default:\n      printf(\" unknown stype\");\n  }\n\n  switch (sym->class) {\n    case C_GLOBAL:\n      printf(\": global\");\n      break;\n    case C_LOCAL:\n      printf(\": local\");\n      break;\n    case C_PARAM:\n      printf(\": param\");\n      break;\n    case C_EXTERN:\n      printf(\": extern\");\n      break;\n    case C_STATIC:\n      printf(\": static\");\n      break;\n    case C_STRUCT:\n      printf(\": struct\");\n      break;\n    case C_UNION:\n      printf(\": union\");\n      break;\n    case C_MEMBER:\n      printf(\": member\");\n      break;\n    case C_ENUMTYPE:\n      printf(\": enumtype\");\n      break;\n    case C_ENUMVAL:\n      printf(\": enumval\");\n      break;\n    case C_TYPEDEF:\n      printf(\": typedef\");\n      break;\n    default:\n      printf(\": unknown class\");\n  }\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      if (sym->class == C_ENUMVAL)\n\tprintf(\", value %d\\n\", sym->st_posn);\n      else\n\tprintf(\", size %d\\n\", sym->size);\n      break;\n    case S_FUNCTION:\n      printf(\", %d params\\n\", sym->nelems);\n      break;\n    case S_ARRAY:\n      printf(\", %d elems, size %d\\n\", sym->nelems, sym->size);\n      break;\n  }\n\n  switch (sym->type & (~0xf)) {\n    case P_STRUCT:\n    case P_UNION:\n      dumptable(sym->member, NULL, 4);\n  }\n\n  switch (sym->stype) {\n    case S_FUNCTION:\n      dumptable(sym->member, NULL, 4);\n  }\n}\n\n// Dump one symbol table\nvoid dumptable(struct symtable *head, char *name, int indent) {\n  struct symtable *sym;\n\n  if (head != NULL && name != NULL)\n    printf(\"%s\\n--------\\n\", name);\n  for (sym = head; sym != NULL; sym = sym->next)\n    dumpsym(sym, indent);\n}\n\nvoid dumpsymtables(void) {\n  dumptable(Globhead, \"Global\", 0);\n  printf(\"\\n\");\n  dumptable(Enumhead, \"Enums\", 0);\n  printf(\"\\n\");\n  dumptable(Typehead, \"Typedefs\", 0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input032.c",
    "content": "Unknown variable or function:pizza on line 4 of input032.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input042.c",
    "content": "Unknown variable or function:fred on line 3 of input042.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input043.c",
    "content": "Unknown variable or function:b on line 3 of input043.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input044.c",
    "content": "Unknown variable or function:z on line 3 of input044.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input059.c",
    "content": "Unknown variable or function:y on line 3 of input059.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input060.c",
    "content": "Expression is not a struct/union on line 3 of input060.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input061.c",
    "content": "Expression is not a pointer to a struct/union on line 3 of input061.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input093.c",
    "content": "Unknown variable or function:fred on line 1 of input093.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input124.c",
    "content": "Cannot ++ on rvalue on line 6 of input124.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input126.c",
    "content": "Unknown variable or function:ptr on line 7 of input126.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/err.input129.c",
    "content": "Cannot ++ and/or -- more than once on line 6 of input129.c\n"
  },
  {
    "path": "54_Reg_Spills/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input034.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int a[12];\n return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "54_Reg_Spills/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "54_Reg_Spills/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "54_Reg_Spills/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "54_Reg_Spills/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "54_Reg_Spills/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "54_Reg_Spills/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "54_Reg_Spills/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "54_Reg_Spills/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "54_Reg_Spills/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "54_Reg_Spills/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "54_Reg_Spills/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "54_Reg_Spills/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "54_Reg_Spills/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "54_Reg_Spills/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "54_Reg_Spills/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "54_Reg_Spills/tests/input097.c",
    "content": "int main() {\n int x[45];\n return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "54_Reg_Spills/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input122.c",
    "content": "#include <stdio.h>\n\nint x, y, z1, z2;\n\nint main() {\n  for (x= 0; x <= 1; x++) {\n    for (y= 0; y <= 1; y++) {\n      z1= x || y; z2= x && y;\n      printf(\"x %d, y %d, x || y %d, x && y %d\\n\", x, y, z1, z2);\n    }\n  }\n  \n  //z= x || y;\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input123.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  for (x=0; x < 20; x++)\n    switch(x) {\n      case 2:\n      case 3:\n      case 5:\n      case 7:\n      case 11: printf(\"%2d infant prime\\n\", x); break;\n      case 13:\n      case 17:\n      case 19: printf(\"%2d teen   prime\\n\", x); break;\n      case 0:\n      case 1:\n      case 4:\n      case 6:\n      case 8:\n      case 9:\n      case 10:\n      case 12: printf(\"%2d infant composite\\n\", x); break;\n      default: printf(\"%2d teen   composite\\n\", x); break;\n    }\n\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input124.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary++;\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input125.c",
    "content": "#include <stdio.h>\n\nint ary[5];\nint *ptr;\nint x;\n\nint main() {\n  ary[3]= 2008;\n  ptr= ary;\t\t\t// Load ary's address into ptr\n  x= ary[3]; printf(\"%d\\n\", x);\n  x= ptr[3]; printf(\"%d\\n\", x); // Treat ptr as an array\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input126.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary[3]= 2008;\n  ptr= &ary;\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input127.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nvoid fred(int *ptr) {\t\t// Receive a pointer\n  printf(\"%d\\n\", ptr[3]);\n}\n\nint main() {\n  ary[3]= 2008;\n  printf(\"%d\\n\", ary[3]);\n  fred(ary);\t\t\t// Pass ary as a pointer\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input128.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int val;\n  struct foo *next;\n};\n\nstruct foo head, mid, tail;\n\nint main() {\n  struct foo *ptr;\n  tail.val= 20; tail.next= NULL;\n  mid.val= 15; mid.next= &tail;\n  head.val= 10; head.next= &mid;\n\n  ptr= &head;\n  printf(\"%d %d\\n\", head.val, ptr->val);\n  printf(\"%d %d\\n\", mid.val, ptr->next->val);\n  printf(\"%d %d\\n\", tail.val, ptr->next->next->val);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input129.c",
    "content": "#include <stdio.h>\n\nint x= 6;\n\nint main() {\n  printf(\"%d\\n\", x++ ++);\n  return(0);\n}\n\n"
  },
  {
    "path": "54_Reg_Spills/tests/input130.c",
    "content": "#include <stdio.h>\n\nchar *x= \"foo\";\n\nint main() {\n  printf(\"Hello \" \"world\" \"\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input131.c",
    "content": "#include <stdio.h>\n\nvoid donothing() { }\n\nint main() {\n  int x=0;\n  printf(\"Doing nothing... \"); donothing();\n  printf(\"nothing done\\n\");\n\n  while (++x < 100) ;\n  printf(\"x is now %d\\n\", x);\n\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input132.c",
    "content": "extern int fred;\nint fred;\n\nint mary;\nextern int mary;\n\nint main() { return(0); }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input133.c",
    "content": "#include <stdio.h>\n\nextern int fred[];\nint fred[23];\n\nchar mary[100];\nextern char mary[];\n\nvoid main() { printf(\"OK\\n\"); }\n"
  },
  {
    "path": "54_Reg_Spills/tests/input134.c",
    "content": "#include <stdio.h>\n\nchar y = 'a';\nchar *x;\n\nint main() {\n  x= &y;        if (x && y == 'a') printf(\"1st match\\n\");\n  x= NULL;      if (x && y == 'a') printf(\"2nd match\\n\");\n  x= &y; y='b'; if (x && y == 'a') printf(\"3rd match\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input135.c",
    "content": "#include <stdio.h>\n\nvoid fred() {\n  int x= 5;\n  printf(\"testing x\\n\");\n  if (x > 4) return;\n  printf(\"x below 5\\n\");\n}\n\nint main() {\n  fred();\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input136.c",
    "content": "#include <stdio.h>\n\nint add(int x, int y) {\n  return(x+y);\n}\n\nint main() {\n  int result;\n  result= 3 * add(2,3) - 5 * add(4,6);\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input137.c",
    "content": "#include <stdio.h>\n\nint a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8;\n\nint main() {\n  int x;\n  x= ((((((a + b) + c) + d) + e) + f) + g) + h;\n  x= a + (b + (c + (d + (e + (f + (g + h))))));\n  printf(\"x is %d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input138.c",
    "content": "#include <stdio.h>\n\nint x, y, z;\n\nint a=1;\nint *aptr;\n\nint main() {\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x && y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x || y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // Now some lazy evaluation\n  aptr= NULL;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  aptr= &a;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/input139.c",
    "content": "#include <stdio.h>\n\nint same(int x) { return(x); }\n\nint main() {\n  int a= 3;\n\n  if (same(a) && same(a) >= same(a))\n    printf(\"same apparently\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "54_Reg_Spills/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input122.c",
    "content": "x 0, y 0, x || y 0, x && y 0\nx 0, y 1, x || y 1, x && y 0\nx 1, y 0, x || y 1, x && y 0\nx 1, y 1, x || y 1, x && y 1\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input123.c",
    "content": " 0 infant composite\n 1 infant composite\n 2 infant prime\n 3 infant prime\n 4 infant composite\n 5 infant prime\n 6 infant composite\n 7 infant prime\n 8 infant composite\n 9 infant composite\n10 infant composite\n11 infant prime\n12 infant composite\n13 teen   prime\n14 teen   composite\n15 teen   composite\n16 teen   composite\n17 teen   prime\n18 teen   composite\n19 teen   prime\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input125.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input127.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input128.c",
    "content": "10 10\n15 15\n20 20\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input130.c",
    "content": "Hello world\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input131.c",
    "content": "Doing nothing... nothing done\nx is now 100\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input132.c",
    "content": ""
  },
  {
    "path": "54_Reg_Spills/tests/out.input133.c",
    "content": "OK\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input134.c",
    "content": "1st match\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input135.c",
    "content": "testing x\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input136.c",
    "content": "-35\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input137.c",
    "content": "x is 36\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input138.c",
    "content": "0 0 | 0\n0 1 | 0\n1 0 | 0\n1 1 | 1\n0 0 | 0\n0 1 | 1\n1 0 | 1\n1 1 | 1\naptr is NULL or doesn't point at 1\naptr points at 1\n"
  },
  {
    "path": "54_Reg_Spills/tests/out.input139.c",
    "content": "same apparently\n"
  },
  {
    "path": "54_Reg_Spills/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "54_Reg_Spills/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "54_Reg_Spills/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->ctype = ctype;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n  int i;\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    case A_TOBOOL:\n      fprintf(stdout, \"A_TOBOOL\\n\");\n      return;\n    case A_LOGOR:\n      fprintf(stdout, \"A_LOGOR\\n\");\n      return;\n    case A_LOGAND:\n      fprintf(stdout, \"A_LOGAND\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "54_Reg_Spills/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n\t\t\t    struct symtable *rctype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // For A_LOGOR and A_LOGAND, both types have to be int or pointer types\n  if (op==A_LOGOR || op==A_LOGAND) {\n    if (!inttype(ltype) && !ptrtype(ltype))\n      return(NULL);\n    if (!inttype(ltype) && !ptrtype(rtype))\n      return(NULL);\n    return (tree);\n  }\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, NULL, tree, NULL, 0));\n  }\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return (tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, rctype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "54_Reg_Spills/zresults",
    "content": "For now, declaration of non-global arrays is not implemented on line 43 of main.c\n"
  },
  {
    "path": "55_Lazy_Evaluation/Readme.md",
    "content": "# Part 55: Lazy Evaluation\n\nI decided to move the coverage of fixing `&&` and `||` to here instead\nof in the previous part of our compiler writing journey as the previous\npart was already big enough.\n\nSo why was our original implementation of `&&` and `||` flawed?\nC programmers expect that these operators will perform\n[lazy evaluation](https://en.wikipedia.org/wiki/Lazy_evaluation).\nIn other words, the right-hand operand of `&&` and `||` is evaluated\nonly if the left-hand operand's value is not enough to determine the\nresult.\n\nA common use of lazy evaluation is to see if a pointer is pointing at\na specific value, but only if the pointer is actually pointing at something.\nThe `test/input138.c` has an example of this:\n\n```c\n  int *aptr;\n  ...\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n```\n\nWe don't want to evaluate both operands to the `&&` operator: if\n`aptr` is NULL, then the `*aptr == 1` expression will cause a NULL\ndereference and crash the program.\n\n## The Problem\n\nThe problem is that our current implementation of `&&` and `||` *does*\nevaluate both operands. In `genAST()` in `gen.c`:\n\n```c\n  // Get the left and right sub-tree values\n  leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    ...\n    case A_LOGOR:\n      return (cglogor(leftreg, rightreg));\n    case A_LOGAND:\n      return (cglogand(leftreg, rightreg));\n    ...\n  }\n```\n\nWe have to rewrite this to *not* evaluate both operands. Instead,\nwe have to evaluate the left-hand one first. If it is enough to\ngive the result, we can jump to the code to set the result. If not,\nnow we evaluate the right-hand operand. Again, we jump to the\ncode to set the result. And if we didn't jump, we must have the\nopposite result.\n\nThis is very much like the code generator for the IF statement, but it is\ndifferent enough that I've written a new code generator in `gen.c`.\nIt gets called *before* we run `genAST()` on the left- and right-hand\noperands. The code is (in stages):\n\n```c\n// Generate the code for an\n// A_LOGAND or A_LOGOR operation\nstatic int gen_logandor(struct ASTnode *n) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n  int reg;\n\n  // Generate the code for the left expression\n  // followed by the jump to the false label\n  reg= genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(NOREG);\n```\n\nThe left operand is evaluated. Let's assume that we are doing the `&&`\noperation. If this result is zero, we can jump down to `Lfalse` and\nset the result to zero (false). Also, once the expression has been\nevaluated we can free all the registers. This also helps to ease the\npressure on register allocation.\n\n```c\n  // Generate the code for the right expression\n  // followed by the jump to the false label\n  reg= genAST(n->right, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(reg);\n```\n\nWe do exactly the same for the right-hand operand. If it was false, we\njump to the `Lfalse` label. If we don't jump, the `&&` result must be\ntrue. For `&&`, we now do:\n\n```c\n  cgloadboolean(reg, 1);\n  cgjump(Lend);\n  cglabel(Lfalse);\n  cgloadboolean(reg, 0);\n  cglabel(Lend);\n  return(reg);\n}\n```\n\nThe `cgloadboolean()` sets the register to true (if 1 is the argument) or\nfalse (if 0 is the argument). For the x86-64 this is 1 and 0, but I've coded\nit this way in case other architectures have different register values for\ntrue and false. The above produces this output for the\nexpression `(aptr && *aptr == 1)`:\n\n```\n        movq    aptr(%rip), %r10\n        test    %r10, %r10              # Test if aptr is not NULL\n        je      L38                     # No, jump to L38\n        movq    aptr(%rip), %r10\n        movslq  (%r10), %r10            # Get *aptr in %r10\n        movq    $1, %r11\n        cmpq    %r11, %r10              # Is *aptr == 1?\n        sete    %r11b\n        movzbq  %r11b, %r11\n        test    %r11, %r11\n        je      L38                     # No, jump to L38\n        movq    $1, %r11                # Both true, true is the result\n        jmp     L39                     # Skip the false code\nL38:\n        movq    $0, %r11                # One or both false, false is the result\nL39:                                    # Continue on with the rest\n```\n\nI haven't given the C code to evaluate the `||` operation. Essentially,\nwe jump if either the left or right is true and set true as the result.\nIf we don't jump, we fall into the code which sets false as the result\nand which jumps over the true setting code.\n\n## Testing the Changes\n\n`test/input138.c` also has code to print out an AND and an OR truth table:\n\n```c\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x && y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x || y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n```\n\nand this produces the output (with a space added):\n\n```\n0 0 | 0\n0 1 | 0\n1 0 | 0\n1 1 | 1\n\n0 0 | 0\n0 1 | 1\n1 0 | 1\n1 1 | 1\n```\n\n## Conclusion and What's Next\n\nNow we have lazy evaluation in the compiler for `&&` and `||`, which we\ndefinitely need for the compiler to compile itself. In fact, at this point,\nthe only thing the compiler can't parse (in its own source code) is the\ndeclaration and use of local arrays. So, guess what...\n\nIn the next part of our compiler writing journey, I'll try to work out\nhow to declare and use local arrays. [Next step](../56_Local_Arrays/Readme.md)\n"
  },
  {
    "path": "56_Local_Arrays/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "56_Local_Arrays/Readme.md",
    "content": "# Part 56: Local Arrays\n\nWell, colour me surprised. It wasn't hard to get local arrays implemented\nat all. It turns out that we had all the pieces in the compiler already,\nwe just had to wire them together.\n\n## Local Array Parsing\n\nLet's start on the parsing side. I want to allow local array declaration\nbut only with a number of elements, no assignment of values.\n\nThe declaration side is easy, we just add these lines to\n`array_declaration()` in `decl.c`:\n\n```c\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    ...\n    case C_LOCAL:\n      sym = addlocl(varname, pointer_to(type), ctype, S_ARRAY, 0);\n      break;\n    ...\n  }\n```\n\nNow, we must prevent assignment to local arrays:\n\n```c\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n```\n\nI also added some more error checking:\n\n```c\n  // Set the size of the array and the number of elements\n  // Only externs can have no elements.\n  if (class != C_EXTERN && nelems<=0)\n    fatals(\"Array must have non-zero elements\", sym->name);\n```\n\nAnd that's it on the declaration side for local arrays.\n\n## Code Generation\n\nIn `cg.c`, we have a function `newlocaloffset()` that calculates the\noffset of a local variable relative to the top of the stack frame. Its\nargument was a primitive type because the compiler only allowed int\nand pointer types as local variables.\n\nNow that each symbol has its size (which `sizeof()` uses), we can change\nthe code in this function to use the symbol's size:\n\n```c\n// Create the position of a new local variable.\nstatic int newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n```\n\nAnd in the code that generates the function's preamble, `cgfuncpreamble()`,\nwe only have to make these changes:\n\n```c\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->size);       // Here\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);     // Here\n  }\n```\n\nThat's it! It possibly means that we can also allow structs and unions\nas local variables. I haven't worried about this yet, but it is something\nto explore later.\n\n## Testing the Changes\n\n`test/input140.c` declares:\n\n```c\nint main() {\n  int  i;\n  int  ary[5];\n  char z;\n  ...\n```\n\nThe array is filled with a FOR loop, `i` being the index. The `z` local\nis also initialised. This checks to see if any of the variables will\ntromp over the other variables. It also checks that we can assign all\nelements of the array and get their values back.\n\nFiles `test/input141.c` and `test/input142.c` check that the compiler\nspots and rejects arrays as parameters and array declarations with no\nelements.\n\n## Conclusion and What's Next\n\nIn the next part of our compiler writing journey, I'll return to mopping\nup duties. [Next step](../57_Mop_up_pt3/Readme.md)\n"
  },
  {
    "path": "56_Local_Arrays/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n\tfatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpopq\\t%s\\n\", reglist[r]);\n}\n\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg=0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      return (reg);\n    }\n  }\n\n  // We have no registers, so we must spill one\n  reg= (spillreg % NUMFREEREGS);\n  spillreg++;\n  fprintf(Outfile, \"# spilling reg %d\\n\", reg);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0) {\n    fprintf(Outfile, \"# error trying to free register %d\\n\", reg);\n    fatald(\"Error trying to free register\", reg);\n  }\n\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg= (spillreg % NUMFREEREGS);\n    fprintf(Outfile, \"# unspilling reg %d\\n\", reg);\n    popreg(reg);\n  } else {\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid spill_all_regs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void unspill_all_regs(void) {\n  int i;\n\n  for (i = NUMFREEREGS-1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\" \"\\t.type\\t%s, @function\\n\", name, name);\n  fprintf(Outfile, \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\" \"\\tmovq\\t%%rsp, %%rbp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->size);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n  freeall_registers(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn,\n\t\treglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn,\n\t\treglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", val, reglist[r]);\n}\n\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch(op) {\n    case A_IF:\n    case A_WHILE:\n    case A_LOGAND:\n      fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n      break;\n    case A_LOGOR:\n      fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n      break;\n    default:\n      fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n      fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n\n  // Unspill all the registers\n  unspill_all_regs();\n\n  // Get a new register and copy the return value into it\n  outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n  free_register(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r],\n\t\tsym->st_posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r],\n\t\tsym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n      case 1:\n\tfprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n\tbreak;\n      case 8:\n\t// Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n\tif (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t    && initvalue != 0)\n\t  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n\telse\n\t  fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n\tbreak;\n      default:\n\tfor (i = 0; i < size; i++)\n\t  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n        case P_CHAR:\n\t  fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n\t  break;\n        case P_INT:\n\t  fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n\t  break;\n        case P_LONG:\n\t  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n\t  break;\n        default:\n\t  fatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovl\\t%s, (%s)\\n\", dreglist[r1], reglist[r2]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n}\n"
  },
  {
    "path": "56_Local_Arrays/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "56_Local_Arrays/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpop\\t%s\\n\", reglist[r]);\n}\n\n// Set all registers as available\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg=0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      return (reg);\n    }\n  }\n  // We have no registers, so we must spill one\n  reg = (spillreg % NUMFREEREGS);\n  spillreg++;\n  fprintf(Outfile, \"; spilling reg %d\\n\", reg);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0) {\n    fprintf(Outfile, \"# error trying to free register %d\\n\", reg);\n    fatald(\"Error trying to free register\", reg);\n  }\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg= (spillreg % NUMFREEREGS);\n    fprintf(Outfile, \"; unspilling reg %d\\n\", reg);\n    popreg(reg);\n  } else {\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid spill_all_regs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void unspill_all_regs(void) {\n  int i;\n\n  for (i = NUMFREEREGS-1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  fputs(\"\\textern\\tprintint\\n\", Outfile);\n  fputs(\"\\textern\\tprintchar\\n\", Outfile);\n  fputs(\"\\textern\\topen\\n\", Outfile);\n  fputs(\"\\textern\\tclose\\n\", Outfile);\n  fputs(\"\\textern\\tread\\n\", Outfile);\n  fputs(\"\\textern\\twrite\\n\", Outfile);\n  fputs(\"\\textern\\tprintf\\n\", Outfile);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", name);\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->size);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n  freeall_registers(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], val);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch(op) {\n    case A_IF:\n    case A_WHILE:\n    case A_LOGAND:\n      fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n      break;\n    case A_LOGOR:\n      fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n      break;\n    default:\n      fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // Unspill all the registers\n  unspill_all_regs();\n  // Get a new register and copy the return value into it\n  outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n  free_register(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n        case P_CHAR:\n          fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n          break;\n        case P_INT:\n          fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n          break;\n        case P_LONG:\n          fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n          break;\n        default:\n          fatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmov\\t[%s], dword %s\\n\", reglist[r2], dreglist[r1]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n}\n"
  },
  {
    "path": "56_Local_Arrays/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Linestart;\t\t     \t// True if at start of a line\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\nextern char *Tstring[];\t\t\t// List of token strings\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_dumpsym;\t\t// If true, dump the symbol table\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "56_Local_Arrays/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Get the type inside the parentheses\n  type = parse_stars(parse_type(ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return (type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree = optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type = tree->type;\n    tree = tree->left;\n  }\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return (tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue == 0)\n      return (0);\n  }\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return (tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a pointer to a symbol that may already exist\n// return true if this symbol doesn't exist. We use\n// this function to convert externs into globals\nint is_new_symbol(struct symtable *sym, int class, \n\t\t  int type, struct symtable *ctype) {\n\n  // There is no existing symbol, thus is new\n  if (sym==NULL) return(1);\n\n  // global versus extern: if they match that it's not new\n  // and we can convert the class to global\n  if ((sym->class== C_GLOBAL && class== C_EXTERN)\n      || (sym->class== C_EXTERN && class== C_GLOBAL)) {\n\n      // If the types don't match, there's a problem\n      if (type != sym->type)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // Struct/unions, also compare the ctype\n      if (type >= P_STRUCT && ctype != sym->ctype)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // If we get to here, the types match, so mark the symbol\n      // as global\n      sym->class= C_GLOBAL;\n      // Return that symbol is not new\n      return(0);\n  }\n\n  // It must be a duplicate symbol if we get here\n  fatals(\"Duplicate global variable declaration\", sym->name);\n  return(-1);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree = NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, type, ctype))\n        sym = addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym = addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym = addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist = (int *) malloc(sizeof(int));\n      sym->initlist[0] = parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym->ctype, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, varnode->ctype, 0);\n      if (exprnode == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode->ctype, exprnode,\n\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t\t// New symbol table entry\n  int nelems = -1;\t\t// Assume the number of elements won't be given\n  int maxelems;\t\t\t// The maximum number of elements in the init list\n  int *initlist;\t\t// The list of initial elements \n  int i = 0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems = parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, pointer_to(type), ctype))\n        sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class, 0, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, pointer_to(type), ctype, S_ARRAY, 0);\n      break;\n    default:\n      fatal(\"Declaration of array parameters is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems = nelems;\n    else\n      maxelems = TABLE_INCREMENT;\n    initlist = (int *) malloc(maxelems * sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n\tfatal(\"Too many values in initialisation list\");\n\n      initlist[i++] = parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n\tmaxelems += TABLE_INCREMENT;\n\tinitlist = (int *) realloc(initlist, maxelems * sizeof(int));\n      }\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n\tscan(&Token);\n\tbreak;\n      }\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j = i; j < sym->nelems; j++)\n      initlist[j] = 0;\n    if (i > nelems)\n      nelems = i;\n    sym->initlist = initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  // Only externs can have no elements.\n  if (class != C_EXTERN && nelems<=0)\n    fatals(\"Array must have non-zero elements\", sym->name);\n\n  sym->nelems = nelems;\n  sym->size = sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n\tparamcnt = 0;\n\tscan(&Token);\n\tbreak;\n      }\n    }\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, ctype, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree = optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t = declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t == -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead == NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name = NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET) {\n    sym = array_declaration(varname, type, ctype, class);\n    *tree= NULL;\t// Local arrays are not initialised\n  } else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree = NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n\tfatal(\"Function definition not at global level\");\n      return (type);\n    }\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree == NULL)\n      *gluetree = tree;\n    else\n      *gluetree =\n\tmkastnode(A_GLUE, P_NONE, NULL, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n  return(0);\t// Keep -Wall happy\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype= NULL;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "56_Local_Arrays/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int level);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue, int append);\nvoid genglobstrend(void);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nint alloc_register(void);\nvoid freeall_registers(int keepreg);\nvoid spill_all_regs(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue, int append);\nvoid cgglobstrend(void);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nvoid cgloadboolean(int r, int val);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\nvoid dumptable(struct symtable *head, char *name, int indent);\nvoid dumpsymtables(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(struct symtable **ctype);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n                            struct symtable *rctype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "56_Local_Arrays/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -w-ptr -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_QUESTION, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\t// 1\n  A_TERNARY, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\t\t// 6\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\t// 12\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\t\t\t// 20\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\t\t\t\t// 24\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\t\t\t// 28\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\t\t\t\t// 33\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\t\t\t// 37\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\t\t// 41\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\t\t// 46\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "56_Local_Arrays/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree =\n      mkastnode(A_GLUE, P_NONE, NULL, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree =\n    mkastunary(A_FUNCCALL, funcptr->type, funcptr->ctype, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(struct ASTnode *left) {\n  struct ASTnode *right;\n\n  // Check that the sub-tree is a pointer\n  if (!ptrtype(left->type))\n    fatal(\"Not an array or pointer\");\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, left->ctype, A_ADD);\n\n  // Return an AST tree where the array's base has the offset added to it,\n  // and dereference the element. Still an lvalue at this point.\n  left =\n    mkastnode(A_ADD, left->type, left->ctype, left, NULL, right, NULL, 0);\n  left =\n    mkastunary(A_DEREF, value_at(left->type), left->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(struct ASTnode *left, int withpointer) {\n  struct ASTnode *right;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the left AST tree is a pointer to struct or union\n  if (withpointer && left->type != pointer_to(P_STRUCT)\n      && left->type != pointer_to(P_UNION))\n    fatal(\"Expression is not a pointer to a struct/union\");\n\n  // Or, check that the left AST tree is a struct or union.\n  // If so, change it from an A_IDENT to an A_ADDR so that\n  // we get the base address, not the value at this address.\n  if (!withpointer) {\n    if (left->type == P_STRUCT || left->type == P_UNION)\n      left->op = A_ADDR;\n    else\n      fatal(\"Expression is not a struct/union\");\n  }\n\n  // Get the details of the composite type\n  typeptr = left->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left =\n    mkastnode(A_ADD, pointer_to(m->type), m->ctype, left, NULL, right, NULL,\n\t      0);\n  left = mkastunary(A_DEREF, m->type, m->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse a parenthesised expression and\n// return an AST node representing it.\nstatic struct ASTnode *paren_expression(void) {\n  struct ASTnode *n;\n  int type = 0;\n  struct symtable *ctype = NULL;\n\n  // Beginning of a parenthesised expression, skip the '('.\n  scan(&Token);\n\n  // If the token after is a type identifier, this is a cast expression\n  switch (Token.token) {\n  case T_IDENT:\n    // We have to see if the identifier matches a typedef.\n    // If not, treat it as an expression.\n    if (findtypedef(Text) == NULL) {\n      n = binexpr(0);\n      break;\n    }\n  case T_VOID:\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n  case T_STRUCT:\n  case T_UNION:\n  case T_ENUM:\n    // Get the type inside the parentheses\n    type = parse_cast(&ctype);\n\n    // Skip the closing ')' and then parse the following expression\n    rparen();\n\n  default:\n    n = binexpr(0);\t\t// Scan in the expression\n  }\n\n  // We now have at least an expression in n, and possibly a non-zero type\n  // in type if there was a cast. Skip the closing ')' if there was no cast.\n  if (type == 0)\n    rparen();\n  else\n    // Otherwise, make a unary AST node for the cast\n    n = mkastunary(A_CAST, type, ctype, n, NULL, 0);\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(void) {\n  struct ASTnode *n;\n  struct symtable *enumptr;\n  struct symtable *varptr;\n  int id;\n  int type = 0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type = parse_stars(parse_type(&ctype, &class));\n\n    // Get the type's size\n    size = typesize(type, ctype);\n    rparen();\n\n    // Make a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    id = genglobstr(Text, 0);\n\n    // For successive STRLIT tokens, append their contents\n    // to this one\n    while (1) {\n      scan(&Peektoken);\n      if (Peektoken.token != T_STRLIT) break;\n      genglobstr(Text, 1);\n      scan(&Token);\t// To skip it properly\n    }\n\n    // Now make a leaf AST node for it. id is the string's label.\n    genglobstrend();\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, NULL, id);\n    break;\n\n  case T_IDENT:\n    // If the identifier matches an enum value,\n    // return an A_INTLIT node\n    if ((enumptr = findenumval(Text)) != NULL) {\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, enumptr->st_posn);\n      break;\n    }\n    // See if this identifier exists as a symbol. For arrays, set rvalue to 1.\n    if ((varptr = findsymbol(Text)) == NULL)\n      fatals(\"Unknown variable or function\", Text);\n    switch (varptr->stype) {\n    case S_VARIABLE:\n      n = mkastleaf(A_IDENT, varptr->type, varptr->ctype, varptr, 0);\n      break;\n    case S_ARRAY:\n      n = mkastleaf(A_ADDR, varptr->type, varptr->ctype, varptr, 0);\n      n->rvalue = 1;\n      break;\n    case S_FUNCTION:\n      // Function call, see if the next token is a left parenthesis\n      scan(&Token);\n      if (Token.token != T_LPAREN)\n\tfatals(\"Function name used without parentheses\", Text);\n      return (funccall());\n    default:\n      fatals(\"Identifier not a scalar or array variable\", Text);\n    }\n    break;\n\n  case T_LPAREN:\n    return (paren_expression());\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(void) {\n  struct ASTnode *n;\n\n  // Get the primary expression\n  n = primary();\n\n  // Loop until there are no more postfix operators\n  while (1) {\n    switch (Token.token) {\n    case T_LBRACKET:\n      // An array reference\n      n = array_access(n);\n      break;\n\n    case T_DOT:\n      // Access into a struct or union\n      n = member_access(n, 0);\n      break;\n\n    case T_ARROW:\n      // Pointer access into a struct or union\n      n = member_access(n, 1);\n      break;\n\n    case T_INC:\n      // Post-increment: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot ++ on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTINC;\n      break;\n\n    case T_DEC:\n      // Post-decrement: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot -- on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTDEC;\n      break;\n\n    default:\n      return (n);\n    }\n  }\n\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatals(\"Token with no precedence in op_precedence:\", Tstring[tokentype]);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (prec);\n}\n\n// prefix_expression: postfix_expression\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstruct ASTnode *prefix(void) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Prevent '&' being performed on an array\n    if (tree->sym->stype == S_ARRAY)\n      fatal(\"& operator cannot be performed on an array\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's either another deref or an\n    // identifier\n    if (tree->op != A_IDENT && tree->op != A_DEREF)\n      fatal(\"* operator must be followed by an identifier or *\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree =\n      mkastunary(A_DEREF, value_at(tree->type), tree->ctype, tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this if needed to int so that it's signed\n    tree->rvalue = 1;\n    if (tree->type == P_CHAR)\n      tree->type = P_INT;\n    tree = mkastunary(A_NEGATE, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix();\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  default:\n    tree = postfix();\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp = binexpr(0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. XXX We should also\n      // consider the third expression's type.\n      return (mkastnode\n\t      (A_TERNARY, right->type, right->ctype, left, right, ltemp,\n\t       NULL, 0));\n\n    case A_ASSIGN:\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, left->ctype, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n      break;\n\n    default:\n      // We are not doing a ternary or assignment, so both trees should\n      // be rvalues. Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, right->ctype, ASTop);\n      rtemp = modify_type(right, left->type, left->ctype, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left->ctype, left, NULL,\n\t\tright, NULL, 0);\n\n    // Some operators produce an int result regardless of their operands\n    switch (binastop(tokentype)) {\n    case A_LOGOR:\n    case A_LOGAND:\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      left->type = P_INT;\n    }\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "56_Local_Arrays/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs(reg);\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    if (c->left)\n      genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs(NOREG);\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for an\n// A_LOGAND or A_LOGOR operation\nstatic int gen_logandor(struct ASTnode *n) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n  int reg;\n\n  // Generate the code for the left expression\n  // followed by the jump to the false label\n  reg= genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(NOREG);\n\n  // Generate the code for the right expression\n  // followed by the jump to the false label\n  reg= genAST(n->right, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(reg);\n\n  // We didn't jump so set the right boolean value\n  if (n->op== A_LOGAND) {\n    cgloadboolean(reg, 1);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 0);\n  } else {\n    cgloadboolean(reg, 0);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 1);\n  }\n  cglabel(Lend);\n  return(reg);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // Save the registers before we copy the arguments\n  spill_all_regs();\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg= NOREG, rightreg= NOREG;\n\n  // Empty tree, do nothing\n  if (n==NULL) return(NOREG);\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_TERNARY:\n      return (gen_ternary(n));\n    case A_LOGOR:\n      return (gen_logandor(n));\n    case A_LOGAND:\n      return (gen_logandor(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL)\n\tgenAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs(NOREG);\n      if (n->right != NULL)\n\tgenAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs(NOREG);\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF, A_WHILE or A_TERNARY,\n      // generate a compare followed by a jump. Otherwise, compare\n      // registers and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE ||\n\t  parentASTop == A_TERNARY)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->a_intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->a_intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n\tcase A_ASPLUS:\n\t  leftreg = cgadd(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASMINUS:\n\t  leftreg = cgsub(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSTAR:\n\t  leftreg = cgmul(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSLASH:\n\t  leftreg = cgdiv(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL ||\n\t      n->right->sym->class == C_STATIC)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->a_size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL || n->left->sym->class == C_STATIC)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (leftreg);\t\t// Not much to do\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs(int keepreg) {\n  freeall_registers(keepreg);\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\n\n// Generate a global string.\n// If append is true, append to\n// previous genglobstr() call.\nint genglobstr(char *strvalue, int append) {\n  int l = genlabel();\n  cgglobstr(l, strvalue, append);\n  return (l);\n}\nvoid genglobstrend(void) {\n  cgglobstrend();\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "56_Local_Arrays/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\nint toupper(int c);\nint tolower(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "56_Local_Arrays/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "56_Local_Arrays/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "56_Local_Arrays/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "56_Local_Arrays/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n#ifndef EOF\n# define EOF (-1)\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint fgetc(FILE *stream);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "56_Local_Arrays/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "56_Local_Arrays/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\nint strcmp(char *s1, char *s2);\nint strncmp(char *s1, char *s2, size_t n);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "56_Local_Arrays/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "56_Local_Arrays/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix;\n  posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Linestart = 1;\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token = 0;\t\t// and set there is no lookahead token\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n\n  // Dump the symbol table if requested\n  if (O_dumpsym) {\n    printf(\"Symbols for %s\\n\", filename);\n    dumpsymtables();\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char *objlist[]) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcSTM] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -M dump the symbol table for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_dumpsym = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'M':\n\t  O_dumpsym = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "56_Local_Arrays/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "56_Local_Arrays/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  int i;\n  for (i = 0; s[i] != '\\0'; i++)\n    if (s[i] == (char) c)\n      return (i);\n  return (-1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (Linestart && c == '#') {\t// We've hit a pre-processor statement\n    Linestart = 0;\t\t// No longer at the start of the line\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n\n  Linestart = 0;\t\t// No longer at the start of the line\n  if ('\\n' == c) {\n    Line++;\t\t\t// Increment line count\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return (n);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn (hexchar());\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = (char)c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = (char)c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "56_Local_Arrays/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, NULL, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, NULL, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, NULL, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree= NULL;\n\n  // Ensure we have 'return'\n  match(T_RETURN, \"return\");\n\n  // See if we have a return value\n  if (Token.token == T_LPAREN) {\n    // Can't return a value if function returns P_VOID\n    if (Functionid->type == P_VOID)\n      fatal(\"Can't return from a void function\");\n\n    // Skip the left parenthesis\n    lparen();\n\n    // Parse the following expression\n    tree = binexpr(0);\n\n    // Ensure this is compatible with the function's type\n    tree = modify_type(tree, Functionid->type, Functionid->ctype, 0);\n    if (tree == NULL)\n      fatal(\"Incompatible type to return\");\n\n    // Get the ')'\n    rparen();\n  }\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, NULL, tree, NULL, 0);\n\n  // Get the ';'\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, P_NONE, NULL, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, P_NONE, NULL, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *body, *n, *c;\n  struct ASTnode *casetree = NULL, *casetail;\n  int inloop = 1, casecount = 0;\n  int seendefault = 0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left = binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n = mkastunary(A_SWITCH, P_NONE, NULL, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch (Token.token) {\n\t// Leave the loop when we hit a '}'\n      case T_RBRACE:\n\tif (casecount == 0)\n\t  fatal(\"No cases in switch\");\n\tinloop = 0;\n\tbreak;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token == T_DEFAULT) {\n\t  ASTop = A_DEFAULT;\n\t  seendefault = 1;\n\t  scan(&Token);\n\t} else {\n\t  ASTop = A_CASE;\n\t  scan(&Token);\n\t  left = binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue = left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n\t  // that there isn't a duplicate case value\n\t  for (c = casetree; c != NULL; c = c->right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n\t}\n\n\t// Scan the ':' and increment the casecount\n\tmatch(T_COLON, \":\");\n\tcasecount++;\n\n\t// If the next token is a T_CASE, the existing case will fall\n\t// into the next case. Otherwise, parse the case body.\n\tif (Token.token == T_CASE)\n\t  body = NULL;\n\telse\n\t  body = compound_statement(1);\n\n\t// Build a sub-tree with any compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree == NULL) {\n\t  casetree = casetail =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t} else {\n\t  casetail->right =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t  casetail = casetail->right;\n\t}\n\tbreak;\n      default:\n\tfatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue = casecount;\n  n->right = casetree;\n  rbrace();\n\n  return (n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_SEMI:\n      // An empty statement\n      semi();\n      break;\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return (stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt = binexpr(0);\n\tsemi();\n\treturn (stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt = binexpr(0);\n      semi();\n      return (stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Leave if we've hit the end token. We do this first to allow\n    // an empty compound statement\n    if (Token.token == T_RBRACE)\n      return (left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT))\n      return (left);\n\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, NULL, left, NULL, tree, NULL, 0);\n    }\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n"
  },
  {
    "path": "56_Local_Arrays/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list,\n\t\t\t\t      int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class == 0 || class == list->class)\n\treturn (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead = Globtail = NULL;\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Membhead = Membtail = NULL;\n  Structhead = Structtail = NULL;\n  Unionhead = Uniontail = NULL;\n  Enumhead = Enumtail = NULL;\n  Typehead = Typetail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev = NULL;\n\n  // Walk the global table looking for static entries\n  for (g = Globhead; g != NULL; g = g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL)\n\tprev->next = g->next;\n      else\n\tGlobhead->next = g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n\tif (prev != NULL)\n\t  Globtail = prev;\n\telse\n\t  Globtail = Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev = g;\n}\n\n// Dump a single symbol\nstatic void dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n    case P_VOID:\n      printf(\"void \");\n      break;\n    case P_CHAR:\n      printf(\"char \");\n      break;\n    case P_INT:\n      printf(\"int \");\n      break;\n    case P_LONG:\n      printf(\"long \");\n      break;\n    case P_STRUCT:\n      if (sym->ctype != NULL)\n\tprintf(\"struct %s \", sym->ctype->name);\n      else\n\tprintf(\"struct %s \", sym->name);\n      break;\n    case P_UNION:\n      if (sym->ctype != NULL)\n\tprintf(\"union %s \", sym->ctype->name);\n      else\n\tprintf(\"union %s \", sym->name);\n      break;\n    default:\n      printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++)\n    printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      break;\n    case S_FUNCTION:\n      printf(\"()\");\n      break;\n    case S_ARRAY:\n      printf(\"[]\");\n      break;\n    default:\n      printf(\" unknown stype\");\n  }\n\n  switch (sym->class) {\n    case C_GLOBAL:\n      printf(\": global\");\n      break;\n    case C_LOCAL:\n      printf(\": local\");\n      break;\n    case C_PARAM:\n      printf(\": param\");\n      break;\n    case C_EXTERN:\n      printf(\": extern\");\n      break;\n    case C_STATIC:\n      printf(\": static\");\n      break;\n    case C_STRUCT:\n      printf(\": struct\");\n      break;\n    case C_UNION:\n      printf(\": union\");\n      break;\n    case C_MEMBER:\n      printf(\": member\");\n      break;\n    case C_ENUMTYPE:\n      printf(\": enumtype\");\n      break;\n    case C_ENUMVAL:\n      printf(\": enumval\");\n      break;\n    case C_TYPEDEF:\n      printf(\": typedef\");\n      break;\n    default:\n      printf(\": unknown class\");\n  }\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      if (sym->class == C_ENUMVAL)\n\tprintf(\", value %d\\n\", sym->st_posn);\n      else\n\tprintf(\", size %d\\n\", sym->size);\n      break;\n    case S_FUNCTION:\n      printf(\", %d params\\n\", sym->nelems);\n      break;\n    case S_ARRAY:\n      printf(\", %d elems, size %d\\n\", sym->nelems, sym->size);\n      break;\n  }\n\n  switch (sym->type & (~0xf)) {\n    case P_STRUCT:\n    case P_UNION:\n      dumptable(sym->member, NULL, 4);\n  }\n\n  switch (sym->stype) {\n    case S_FUNCTION:\n      dumptable(sym->member, NULL, 4);\n  }\n}\n\n// Dump one symbol table\nvoid dumptable(struct symtable *head, char *name, int indent) {\n  struct symtable *sym;\n\n  if (head != NULL && name != NULL)\n    printf(\"%s\\n--------\\n\", name);\n  for (sym = head; sym != NULL; sym = sym->next)\n    dumpsym(sym, indent);\n}\n\nvoid dumpsymtables(void) {\n  dumptable(Globhead, \"Global\", 0);\n  printf(\"\\n\");\n  dumptable(Enumhead, \"Enums\", 0);\n  printf(\"\\n\");\n  dumptable(Typehead, \"Typedefs\", 0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input032.c",
    "content": "Unknown variable or function:pizza on line 4 of input032.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input042.c",
    "content": "Unknown variable or function:fred on line 3 of input042.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input043.c",
    "content": "Unknown variable or function:b on line 3 of input043.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input044.c",
    "content": "Unknown variable or function:z on line 3 of input044.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input046.c",
    "content": "* operator must be followed by an identifier or * on line 3 of input046.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input059.c",
    "content": "Unknown variable or function:y on line 3 of input059.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input060.c",
    "content": "Expression is not a struct/union on line 3 of input060.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input061.c",
    "content": "Expression is not a pointer to a struct/union on line 3 of input061.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input093.c",
    "content": "Unknown variable or function:fred on line 1 of input093.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input124.c",
    "content": "Cannot ++ on rvalue on line 6 of input124.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input126.c",
    "content": "Unknown variable or function:ptr on line 7 of input126.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input129.c",
    "content": "Cannot ++ and/or -- more than once on line 6 of input129.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input141.c",
    "content": "Declaration of array parameters is not implemented on line 4 of input141.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/err.input142.c",
    "content": "Array must have non-zero elements:fred on line 1 of input142.c\n"
  },
  {
    "path": "56_Local_Arrays/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "56_Local_Arrays/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "56_Local_Arrays/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "56_Local_Arrays/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "56_Local_Arrays/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "56_Local_Arrays/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "56_Local_Arrays/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "56_Local_Arrays/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "56_Local_Arrays/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "56_Local_Arrays/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "56_Local_Arrays/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "56_Local_Arrays/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "56_Local_Arrays/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "56_Local_Arrays/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "56_Local_Arrays/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "56_Local_Arrays/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "56_Local_Arrays/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "56_Local_Arrays/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input122.c",
    "content": "#include <stdio.h>\n\nint x, y, z1, z2;\n\nint main() {\n  for (x= 0; x <= 1; x++) {\n    for (y= 0; y <= 1; y++) {\n      z1= x || y; z2= x && y;\n      printf(\"x %d, y %d, x || y %d, x && y %d\\n\", x, y, z1, z2);\n    }\n  }\n  \n  //z= x || y;\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input123.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  for (x=0; x < 20; x++)\n    switch(x) {\n      case 2:\n      case 3:\n      case 5:\n      case 7:\n      case 11: printf(\"%2d infant prime\\n\", x); break;\n      case 13:\n      case 17:\n      case 19: printf(\"%2d teen   prime\\n\", x); break;\n      case 0:\n      case 1:\n      case 4:\n      case 6:\n      case 8:\n      case 9:\n      case 10:\n      case 12: printf(\"%2d infant composite\\n\", x); break;\n      default: printf(\"%2d teen   composite\\n\", x); break;\n    }\n\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input124.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary++;\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input125.c",
    "content": "#include <stdio.h>\n\nint ary[5];\nint *ptr;\nint x;\n\nint main() {\n  ary[3]= 2008;\n  ptr= ary;\t\t\t// Load ary's address into ptr\n  x= ary[3]; printf(\"%d\\n\", x);\n  x= ptr[3]; printf(\"%d\\n\", x); // Treat ptr as an array\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input126.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary[3]= 2008;\n  ptr= &ary;\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input127.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nvoid fred(int *ptr) {\t\t// Receive a pointer\n  printf(\"%d\\n\", ptr[3]);\n}\n\nint main() {\n  ary[3]= 2008;\n  printf(\"%d\\n\", ary[3]);\n  fred(ary);\t\t\t// Pass ary as a pointer\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input128.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int val;\n  struct foo *next;\n};\n\nstruct foo head, mid, tail;\n\nint main() {\n  struct foo *ptr;\n  tail.val= 20; tail.next= NULL;\n  mid.val= 15; mid.next= &tail;\n  head.val= 10; head.next= &mid;\n\n  ptr= &head;\n  printf(\"%d %d\\n\", head.val, ptr->val);\n  printf(\"%d %d\\n\", mid.val, ptr->next->val);\n  printf(\"%d %d\\n\", tail.val, ptr->next->next->val);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input129.c",
    "content": "#include <stdio.h>\n\nint x= 6;\n\nint main() {\n  printf(\"%d\\n\", x++ ++);\n  return(0);\n}\n\n"
  },
  {
    "path": "56_Local_Arrays/tests/input130.c",
    "content": "#include <stdio.h>\n\nchar *x= \"foo\";\n\nint main() {\n  printf(\"Hello \" \"world\" \"\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input131.c",
    "content": "#include <stdio.h>\n\nvoid donothing() { }\n\nint main() {\n  int x=0;\n  printf(\"Doing nothing... \"); donothing();\n  printf(\"nothing done\\n\");\n\n  while (++x < 100) ;\n  printf(\"x is now %d\\n\", x);\n\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input132.c",
    "content": "extern int fred;\nint fred;\n\nint mary;\nextern int mary;\n\nint main() { return(0); }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input133.c",
    "content": "#include <stdio.h>\n\nextern int fred[];\nint fred[23];\n\nchar mary[100];\nextern char mary[];\n\nvoid main() { printf(\"OK\\n\"); }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input134.c",
    "content": "#include <stdio.h>\n\nchar y = 'a';\nchar *x;\n\nint main() {\n  x= &y;        if (x && y == 'a') printf(\"1st match\\n\");\n  x= NULL;      if (x && y == 'a') printf(\"2nd match\\n\");\n  x= &y; y='b'; if (x && y == 'a') printf(\"3rd match\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input135.c",
    "content": "#include <stdio.h>\n\nvoid fred() {\n  int x= 5;\n  printf(\"testing x\\n\");\n  if (x > 4) return;\n  printf(\"x below 5\\n\");\n}\n\nint main() {\n  fred();\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input136.c",
    "content": "#include <stdio.h>\n\nint add(int x, int y) {\n  return(x+y);\n}\n\nint main() {\n  int result;\n  result= 3 * add(2,3) - 5 * add(4,6);\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input137.c",
    "content": "#include <stdio.h>\n\nint a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8;\n\nint main() {\n  int x;\n  x= ((((((a + b) + c) + d) + e) + f) + g) + h;\n  x= a + (b + (c + (d + (e + (f + (g + h))))));\n  printf(\"x is %d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input138.c",
    "content": "#include <stdio.h>\n\nint x, y, z;\n\nint a=1;\nint *aptr;\n\nint main() {\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x && y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x || y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // Now some lazy evaluation\n  aptr= NULL;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  aptr= &a;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input139.c",
    "content": "#include <stdio.h>\n\nint same(int x) { return(x); }\n\nint main() {\n  int a= 3;\n\n  if (same(a) && same(a) >= same(a))\n    printf(\"same apparently\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input140.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int  i;\n  int  ary[5];\n  char z;\n\n  // Write below the array\n  z= 'H';\n\n  // Fill the array\n  for (i=0; i < 5; i++)\n    ary[i]= i * i;\n\n  // Write above the array\n  i=14;\n\n  // Print out the array\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", ary[i]);\n\n  // See if either side is OK\n  printf(\"%d %c\\n\", i, z);\n  return(0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/input141.c",
    "content": "static int fred[5];\nint jim;\n\nint foo(int mary[6]) { return(5); }\n"
  },
  {
    "path": "56_Local_Arrays/tests/input142.c",
    "content": "static int fred[];\nint jim;\n"
  },
  {
    "path": "56_Local_Arrays/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "56_Local_Arrays/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input122.c",
    "content": "x 0, y 0, x || y 0, x && y 0\nx 0, y 1, x || y 1, x && y 0\nx 1, y 0, x || y 1, x && y 0\nx 1, y 1, x || y 1, x && y 1\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input123.c",
    "content": " 0 infant composite\n 1 infant composite\n 2 infant prime\n 3 infant prime\n 4 infant composite\n 5 infant prime\n 6 infant composite\n 7 infant prime\n 8 infant composite\n 9 infant composite\n10 infant composite\n11 infant prime\n12 infant composite\n13 teen   prime\n14 teen   composite\n15 teen   composite\n16 teen   composite\n17 teen   prime\n18 teen   composite\n19 teen   prime\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input125.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input127.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input128.c",
    "content": "10 10\n15 15\n20 20\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input130.c",
    "content": "Hello world\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input131.c",
    "content": "Doing nothing... nothing done\nx is now 100\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input132.c",
    "content": ""
  },
  {
    "path": "56_Local_Arrays/tests/out.input133.c",
    "content": "OK\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input134.c",
    "content": "1st match\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input135.c",
    "content": "testing x\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input136.c",
    "content": "-35\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input137.c",
    "content": "x is 36\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input138.c",
    "content": "0 0 | 0\n0 1 | 0\n1 0 | 0\n1 1 | 1\n0 0 | 0\n0 1 | 1\n1 0 | 1\n1 1 | 1\naptr is NULL or doesn't point at 1\naptr points at 1\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input139.c",
    "content": "same apparently\n"
  },
  {
    "path": "56_Local_Arrays/tests/out.input140.c",
    "content": "0\n1\n4\n9\n16\n5 H\n"
  },
  {
    "path": "56_Local_Arrays/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "56_Local_Arrays/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "56_Local_Arrays/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->ctype = ctype;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n  int i;\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    case A_TOBOOL:\n      fprintf(stdout, \"A_TOBOOL\\n\");\n      return;\n    case A_LOGOR:\n      fprintf(stdout, \"A_LOGOR\\n\");\n      return;\n    case A_LOGAND:\n      fprintf(stdout, \"A_LOGAND\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "56_Local_Arrays/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n\t\t\t    struct symtable *rctype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // For A_LOGOR and A_LOGAND, both types have to be int or pointer types\n  if (op==A_LOGOR || op==A_LOGAND) {\n    if (!inttype(ltype) && !ptrtype(ltype))\n      return(NULL);\n    if (!inttype(ltype) && !ptrtype(rtype))\n      return(NULL);\n    return (tree);\n  }\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, NULL, tree, NULL, 0));\n  }\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return (tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n  // We can scale only on A_ADD or A_SUBTRACT operation\n  if (op == A_ADD || op == A_SUBTRACT) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, rctype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h incdir.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\nincdir.h:\n\techo \"#define INCDIR \\\"$(INCDIR)\\\"\" > incdir.h\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out incdir.h\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "57_Mop_up_pt3/Readme.md",
    "content": "# Part 57: Mopping Up, part 3\n\nIn this part of our compiler writing journey, I fix up a few more small\nissues with the compiler.\n\n## No -D Flag\n\nOur compiler doesn't have a run-time `-D` flag to define a symbol to the\npre-processor, and it would be somewhat complicated to add it in. But we\nuse this in the `Makefile` to set the location of the directory where\nour header files are.\n\nI've rewritten the `Makefile` to write this location into a new header\nfile:\n\n```\n# Define the location of the include directory\nINCDIR=/tmp/include\n...\n\nincdir.h:\n        echo \"#define INCDIR \\\"$(INCDIR)\\\"\" > incdir.h\n```\n\nand in `defs.h` we now have:\n\n```c\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n#include \"incdir.h\"\n```\n\nThis ensures that the location of this directory is known to the source\ncode.\n\n## Loading Extern Variables\n\nI've added these three external variables in `include/stdio.h`:\n\n```c\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n```\n\nbut when I tried to use them they were being treated as local variables!\nIt turns out my logic to choose a global variable was wrong. In\n`genAST()` in `gen.c`, we now have:\n\n```c\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n        if (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC\n            || n->sym->class == C_EXTERN) {\n          return (cgloadglob(n->sym, n->op));\n        } else {\n          return (cgloadlocal(n->sym, n->op));\n        }\n```\n\nwith the `C_EXTERN` alternative being added.\n\n## Problems with the Pratt Parser\n\nWay back in part 3 of this journey, I introduced the\n[Pratt parser](https://en.wikipedia.org/wiki/Pratt_parser)\nwhich has a table of precedence values associated with each token.\nWe've been using it ever since as it works.\n\nHowever, I've introduced tokens that don't get parsed\nby the Pratt parser: prefix operators, postfix operators, casts,\narray element access etc. And along the way I broke the chain that\nensures the Pratt parser knows the precedence of the previous operator\ntoken.\n\nHere is the basic Pratt algorihm again, as shown by the code in\n`binexpr()` in `expr.c`:\n\n```c\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix();\n  tokentype = Token.token;\n\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n         (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Join that sub-tree with ours (code not given)\n\n    // Update the details of the current token.\n    // Leave the loop if a terminating token (code not given)\n    tokentype = Token.token;\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  return (left);\n```\n\nWe must ensure that `binexpr()` gets called with the precedence of\nthe previous token. Now let's look at how this got broken.\n\nConsider this expression that checks if three pointers are valid:\n\n```c\n  if (a == NULL || b == NULL || c == NULL)\n```\n\nThe `==` operator has higher precedence that the `||` operator, so the\nPratt parser should treat this the same as:\n\n```c\n  if ((a == NULL) || (b == NULL) || (c == NULL))\n```\n\nNow, NULL is defined as this expression, and it includes a cast:\n\n```c\n#define NULL (void *)0\n```\n\nSo let's look at the call chain of the IF line above:\n\n + `binexpr(0)` is called from `if_statement()`\n + `binexpr(0)` parses the `==` (which has precedence 40) and\n    calls `binexpr(40)`\n + `binexpr(40)` calls `prefix()`\n + `prefix()` calls `postfix()`\n + `postfix()` calls `primary()`\n + `primary()` sees the left parenthesis at the start of the `(void *)0`\n    and calls `paren_expression()`\n + `paren_expression()` sees the `void` token and calls\n   `parse_cast()`. Once the cast is parsed, it calls `binexpr(0)` to\n    parse the `0`.\n\nAnd that's the problem. The value of NULL, i.e. `0` should still be\nat precedence level 40, but `paren_expression()` just reset it back to\nzero.\n\nThis means that we will now parse `NULL || b`, making an AST tree out of\nit instead of parsing `a == NULL` and building that AST tree.\n\nThe solution is to ensure that the previous token precedence is passed\nthrough the call chain all the way from `binexpr()` up to \n`paren_expression()`. This means that:\n\n + `prefix()`, `postfix()`, `primary()` and `paren_expression()`\n\nall now take an `int ptp` argument and this is passed on.\n\nThe program `tests/input143.c` checks that this change now works\nfor `if (a==NULL || b==NULL || c==NULL)`.\n\n## Pointers, `+=` and `-=`\n\nA while back, I realised that if we were adding an integer value to a\npointer, we needed to scale the integer by the type size that the pointer\npoints at. For example:\n\n```c\nint list[]= {3, 5, 7, 9, 11, 13, 15};\nint *lptr;\n\nint main() {\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n}\n```\n\nshould print the value at the base of `list`, i.e. 3. The `lptr` should\nbe incremented by the *size* of `int`, i.e. 4, so that it now points at\nthe next element in the `list`.\n\nNow, we do this for the `+` and `-` operators, but I forgot to implement\nit for the `+=` and `-=` operators. Fortunately this was easy to fix.\nAt the bottom of `modify_type()` in `types.c`, we now have:\n\n```c\n  // We can scale only on add and subtract operations\n  if (op == A_ADD || op == A_SUBTRACT ||\n      op == A_ASPLUS || op == A_ASMINUS) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n        return (mkastunary(A_SCALE, rtype, rctype, tree, NULL, rsize));\n      else\n        return (tree);          // Size 1, no need to scale\n    }\n  }\n```\n\nYou can see I've added A_ASPLUS and A_ASMINUS to the list of operations\nwhere we can scale an int value.\n\n## Conclusion and What's Next\n\nThat's enough mopping up for now. When I fixed up the `+=` and `-=` problem,\nit highlighted a big issue with the `++` and `--` operators (prefix and\npostfix) as applied to pointers.\n\nIn the next part of our compiler writing journey, I will tackle this issue. [Next step](../58_Ptr_Increments/Readme.md)\n"
  },
  {
    "path": "57_Mop_up_pt3/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n\tfatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpopq\\t%s\\n\", reglist[r]);\n}\n\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  fprintf(Outfile, \"# freeing all registers\\n\");\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg=0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      fprintf(Outfile, \"# allocated register %s\\n\", reglist[reg]);\n      return (reg);\n    }\n  }\n\n  // We have no registers, so we must spill one\n  reg= (spillreg % NUMFREEREGS);\n  spillreg++;\n  fprintf(Outfile, \"# spilling reg %s\\n\", reglist[reg]);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0) {\n    fprintf(Outfile, \"# error trying to free register %s\\n\", reglist[reg]);\n    fatald(\"Error trying to free register\", reg);\n  }\n\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg= (spillreg % NUMFREEREGS);\n    fprintf(Outfile, \"# unspilling reg %s\\n\", reglist[reg]);\n    popreg(reg);\n  } else {\n    fprintf(Outfile, \"# freeing reg %s\\n\", reglist[reg]);\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid spill_all_regs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void unspill_all_regs(void) {\n  int i;\n\n  for (i = NUMFREEREGS-1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop    next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\" \"\\t.type\\t%s, @function\\n\", name, name);\n  fprintf(Outfile, \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\" \"\\tmovq\\t%%rsp, %%rbp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->size);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n  freeall_registers(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%s(%%rip)\\n\", sym->name);\n  } else\n    // Print out the code to initialise it\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tfprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%s(%%rip)\\n\", sym->name);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%s(%%rip)\\n\", sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%d(%%rbp)\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdecq\\t%d(%%rbp)\\n\", sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn,\n\t\treglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecb\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      case P_INT:\n\tif (op == A_PREINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_PREDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tfprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn,\n\t\treglist[r]);\n\tif (op == A_POSTINC)\n\t  fprintf(Outfile, \"\\tincl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tif (op == A_POSTDEC)\n\t  fprintf(Outfile, \"\\tdecl\\t%d(%%rbp)\\n\", sym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgloadlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", val, reglist[r]);\n}\n\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch(op) {\n    case A_IF:\n    case A_WHILE:\n    case A_LOGAND:\n      fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n      break;\n    case A_LOGOR:\n      fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n      break;\n    default:\n      fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n      fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n\n  // Unspill all the registers\n  unspill_all_regs();\n\n  // Get a new register and copy the return value into it\n  outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n  free_register(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r],\n\t\tsym->st_posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r],\n\t\tsym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n      case 1:\n\tfprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n\tbreak;\n      case 8:\n\t// Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n\tif (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t    && initvalue != 0)\n\t  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n\telse\n\t  fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n\tbreak;\n      default:\n\tfor (i = 0; i < size; i++)\n\t  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n        case P_CHAR:\n\t  fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n\t  break;\n        case P_INT:\n\t  fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n\t  break;\n        case P_LONG:\n\t  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n\t  break;\n        default:\n\t  fatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovl\\t%s, (%s)\\n\", dreglist[r1], reglist[r2]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpop\\t%s\\n\", reglist[r]);\n}\n\n// Set all registers as available\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  fprintf(Outfile, \"; freeing all registers\\n\");\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg=0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      fprintf(Outfile, \"; allocated register %s\\n\", reglist[reg]);\n      return (reg);\n    }\n  }\n  // We have no registers, so we must spill one\n  reg = (spillreg % NUMFREEREGS);\n  spillreg++;\n  fprintf(Outfile, \"; spilling reg %s\\n\", reglist[reg]);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0) {\n    fprintf(Outfile, \"# error trying to free register %s\\n\", reglist[reg]);\n    fatald(\"Error trying to free register\", reg);\n  }\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg= (spillreg % NUMFREEREGS);\n    fprintf(Outfile, \"; unspilling reg %s\\n\", reglist[reg]);\n    popreg(reg);\n  } else {\n    fprintf(Outfile, \"; freeing reg %s\\n\", reglist[reg]);\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid spill_all_regs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void unspill_all_regs(void) {\n  int i;\n\n  for (i = NUMFREEREGS-1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"no:\\n\"\n\t  \"        loop   next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", name);\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->size);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n  freeall_registers(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadglob(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n    fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword [%s]\\n\", sym->name);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword [%s]\\n\", sym->name);\n  } else\n  // Print out the code to initialise it\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], \n              sym->name);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte [%s]\\n\", sym->name);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      fprintf(Outfile, \"\\tmovsx\\t%s, word [%s]\\n\", dreglist[r], \n              sym->name);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword [%s]\\n\", sym->name);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword [%s]\\n\", sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Load a value from a local variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadlocal(struct symtable *sym, int op) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Print out the code to initialise it\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_PREDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tinc\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n    if (op == A_POSTDEC)\n      fprintf(Outfile, \"\\tdec\\tqword\\t[rbp+%d]\\n\", sym->st_posn);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tbyte\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    case P_INT:\n      if (op == A_PREINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_PREDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [rbp+%d]\\n\", reglist[r], \n              sym->st_posn);\n      fprintf(Outfile, \"\\tmovsxd\\t%s, %s\\n\", reglist[r], dreglist[r]);\n      if (op == A_POSTINC)\n      if (op == A_POSTINC)\n        fprintf(Outfile, \"\\tinc\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      if (op == A_POSTDEC)\n        fprintf(Outfile, \"\\tdec\\tdword\\t[rbp+%d]\\n\", sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgloadlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], val);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch(op) {\n    case A_IF:\n    case A_WHILE:\n    case A_LOGAND:\n      fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n      break;\n    case A_LOGOR:\n      fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n      break;\n    default:\n      fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // Unspill all the registers\n  unspill_all_regs();\n  // Get a new register and copy the return value into it\n  outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n  free_register(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n        case P_CHAR:\n          fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n          break;\n        case P_INT:\n          fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n          break;\n        case P_LONG:\n          fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n          break;\n        default:\n          fatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmov\\t[%s], dword %s\\n\", reglist[r2], dreglist[r1]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\tswitch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Linestart;\t\t     \t// True if at start of a line\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\nextern char *Tstring[];\t\t\t// List of token strings\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_dumpsym;\t\t// If true, dump the symbol table\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "57_Mop_up_pt3/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Get the type inside the parentheses\n  type = parse_stars(parse_type(ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return (type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree = optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type = tree->type;\n    tree = tree->left;\n  }\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return (tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue == 0)\n      return (0);\n  }\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return (tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a pointer to a symbol that may already exist\n// return true if this symbol doesn't exist. We use\n// this function to convert externs into globals\nint is_new_symbol(struct symtable *sym, int class, \n\t\t  int type, struct symtable *ctype) {\n\n  // There is no existing symbol, thus is new\n  if (sym==NULL) return(1);\n\n  // global versus extern: if they match that it's not new\n  // and we can convert the class to global\n  if ((sym->class== C_GLOBAL && class== C_EXTERN)\n      || (sym->class== C_EXTERN && class== C_GLOBAL)) {\n\n      // If the types don't match, there's a problem\n      if (type != sym->type)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // Struct/unions, also compare the ctype\n      if (type >= P_STRUCT && ctype != sym->ctype)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // If we get to here, the types match, so mark the symbol\n      // as global\n      sym->class= C_GLOBAL;\n      // Return that symbol is not new\n      return(0);\n  }\n\n  // It must be a duplicate symbol if we get here\n  fatals(\"Duplicate global variable declaration\", sym->name);\n  return(-1);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree = NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, type, ctype))\n        sym = addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym = addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym = addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist = (int *) malloc(sizeof(int));\n      sym->initlist[0] = parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym->ctype, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, varnode->ctype, 0);\n      if (exprnode == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode->ctype, exprnode,\n\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t\t// New symbol table entry\n  int nelems = -1;\t\t// Assume the number of elements won't be given\n  int maxelems;\t\t\t// The maximum number of elements in the init list\n  int *initlist;\t\t// The list of initial elements \n  int i = 0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems = parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, pointer_to(type), ctype))\n        sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class, 0, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, pointer_to(type), ctype, S_ARRAY, 0);\n      break;\n    default:\n      fatal(\"Declaration of array parameters is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems = nelems;\n    else\n      maxelems = TABLE_INCREMENT;\n    initlist = (int *) malloc(maxelems * sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n\tfatal(\"Too many values in initialisation list\");\n\n      initlist[i++] = parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n\tmaxelems += TABLE_INCREMENT;\n\tinitlist = (int *) realloc(initlist, maxelems * sizeof(int));\n      }\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n\tscan(&Token);\n\tbreak;\n      }\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j = i; j < sym->nelems; j++)\n      initlist[j] = 0;\n    if (i > nelems)\n      nelems = i;\n    sym->initlist = initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  // Only externs can have no elements.\n  if (class != C_EXTERN && nelems<=0)\n    fatals(\"Array must have non-zero elements\", sym->name);\n\n  sym->nelems = nelems;\n  sym->size = sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n\tparamcnt = 0;\n\tscan(&Token);\n\tbreak;\n      }\n    }\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, ctype, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree = optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t = declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t == -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead == NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name = NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET) {\n    sym = array_declaration(varname, type, ctype, class);\n    *tree= NULL;\t// Local arrays are not initialised\n  } else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree = NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n\tfatal(\"Function definition not at global level\");\n      return (type);\n    }\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree == NULL)\n      *gluetree = tree;\n    else\n      *gluetree =\n\tmkastnode(A_GLUE, P_NONE, NULL, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n  return(0);\t// Keep -Wall happy\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype= NULL;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int level);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue, int append);\nvoid genglobstrend(void);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nint alloc_register(void);\nvoid freeall_registers(int keepreg);\nvoid spill_all_regs(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadglob(struct symtable *sym, int op);\nint cgloadlocal(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdiv(int r1, int r2);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue, int append);\nvoid cgglobstrend(void);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nvoid cgloadboolean(int r, int val);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\nvoid dumptable(struct symtable *head, char *name, int indent);\nvoid dumpsymtables(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(struct symtable **ctype);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n                            struct symtable *rctype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "57_Mop_up_pt3/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n#include \"incdir.h\"\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -w-ptr -pnasmext.inc -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH,\n  T_QUESTION, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR, A_ASSLASH,\t// 1\n  A_TERNARY, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND,\t\t// 6\n  A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\t// 12\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE,\t\t\t// 20\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\t\t\t\t// 24\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\t\t\t// 28\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\t\t\t\t// 33\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\t\t\t// 37\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\t\t// 41\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\t\t// 46\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "57_Mop_up_pt3/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree =\n      mkastnode(A_GLUE, P_NONE, NULL, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree =\n    mkastunary(A_FUNCCALL, funcptr->type, funcptr->ctype, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(struct ASTnode *left) {\n  struct ASTnode *right;\n\n  // Check that the sub-tree is a pointer\n  if (!ptrtype(left->type))\n    fatal(\"Not an array or pointer\");\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, left->ctype, A_ADD);\n\n  // Return an AST tree where the array's base has the offset added to it,\n  // and dereference the element. Still an lvalue at this point.\n  left =\n    mkastnode(A_ADD, left->type, left->ctype, left, NULL, right, NULL, 0);\n  left =\n    mkastunary(A_DEREF, value_at(left->type), left->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(struct ASTnode *left, int withpointer) {\n  struct ASTnode *right;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the left AST tree is a pointer to struct or union\n  if (withpointer && left->type != pointer_to(P_STRUCT)\n      && left->type != pointer_to(P_UNION))\n    fatal(\"Expression is not a pointer to a struct/union\");\n\n  // Or, check that the left AST tree is a struct or union.\n  // If so, change it from an A_IDENT to an A_ADDR so that\n  // we get the base address, not the value at this address.\n  if (!withpointer) {\n    if (left->type == P_STRUCT || left->type == P_UNION)\n      left->op = A_ADDR;\n    else\n      fatal(\"Expression is not a struct/union\");\n  }\n\n  // Get the details of the composite type\n  typeptr = left->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left =\n    mkastnode(A_ADD, pointer_to(m->type), m->ctype, left, NULL, right, NULL,\n\t      0);\n  left = mkastunary(A_DEREF, m->type, m->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse a parenthesised expression and\n// return an AST node representing it.\nstatic struct ASTnode *paren_expression(int ptp) {\n  struct ASTnode *n;\n  int type = 0;\n  struct symtable *ctype = NULL;\n\n  // Beginning of a parenthesised expression, skip the '('.\n  scan(&Token);\n\n  // If the token after is a type identifier, this is a cast expression\n  switch (Token.token) {\n  case T_IDENT:\n    // We have to see if the identifier matches a typedef.\n    // If not, treat it as an expression.\n    if (findtypedef(Text) == NULL) {\n      n = binexpr(0);\t// ptp is zero as expression inside ( )\n      break;\n    }\n  case T_VOID:\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n  case T_STRUCT:\n  case T_UNION:\n  case T_ENUM:\n    // Get the type inside the parentheses\n    type = parse_cast(&ctype);\n\n    // Skip the closing ')' and then parse the following expression\n    rparen();\n\n  default:\n    n = binexpr(ptp);\t\t// Scan in the expression. We pass in ptp\n\t\t\t\t// as the cast doesn't change the\n\t\t\t\t// expression's precedence\n  }\n\n  // We now have at least an expression in n, and possibly a non-zero type\n  // in type if there was a cast. Skip the closing ')' if there was no cast.\n  if (type == 0)\n    rparen();\n  else\n    // Otherwise, make a unary AST node for the cast\n    n = mkastunary(A_CAST, type, ctype, n, NULL, 0);\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(int ptp) {\n  struct ASTnode *n;\n  struct symtable *enumptr;\n  struct symtable *varptr;\n  int id;\n  int type = 0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type = parse_stars(parse_type(&ctype, &class));\n\n    // Get the type's size\n    size = typesize(type, ctype);\n    rparen();\n\n    // Make a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    id = genglobstr(Text, 0);\n\n    // For successive STRLIT tokens, append their contents\n    // to this one\n    while (1) {\n      scan(&Peektoken);\n      if (Peektoken.token != T_STRLIT) break;\n      genglobstr(Text, 1);\n      scan(&Token);\t// To skip it properly\n    }\n\n    // Now make a leaf AST node for it. id is the string's label.\n    genglobstrend();\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, NULL, id);\n    break;\n\n  case T_IDENT:\n    // If the identifier matches an enum value,\n    // return an A_INTLIT node\n    if ((enumptr = findenumval(Text)) != NULL) {\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, enumptr->st_posn);\n      break;\n    }\n    // See if this identifier exists as a symbol. For arrays, set rvalue to 1.\n    if ((varptr = findsymbol(Text)) == NULL)\n      fatals(\"Unknown variable or function\", Text);\n    switch (varptr->stype) {\n    case S_VARIABLE:\n      n = mkastleaf(A_IDENT, varptr->type, varptr->ctype, varptr, 0);\n      break;\n    case S_ARRAY:\n      n = mkastleaf(A_ADDR, varptr->type, varptr->ctype, varptr, 0);\n      n->rvalue = 1;\n      break;\n    case S_FUNCTION:\n      // Function call, see if the next token is a left parenthesis\n      scan(&Token);\n      if (Token.token != T_LPAREN)\n\tfatals(\"Function name used without parentheses\", Text);\n      return (funccall());\n    default:\n      fatals(\"Identifier not a scalar or array variable\", Text);\n    }\n    break;\n\n  case T_LPAREN:\n    return (paren_expression(ptp));\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(int ptp) {\n  struct ASTnode *n;\n\n  // Get the primary expression\n  n = primary(ptp);\n\n  // Loop until there are no more postfix operators\n  while (1) {\n    switch (Token.token) {\n    case T_LBRACKET:\n      // An array reference\n      n = array_access(n);\n      break;\n\n    case T_DOT:\n      // Access into a struct or union\n      n = member_access(n, 0);\n      break;\n\n    case T_ARROW:\n      // Pointer access into a struct or union\n      n = member_access(n, 1);\n      break;\n\n    case T_INC:\n      // Post-increment: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot ++ on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTINC;\n      break;\n\n    case T_DEC:\n      // Post-decrement: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot -- on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTDEC;\n      break;\n\n    default:\n      return (n);\n    }\n  }\n\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_SLASH)\n    return (tokentype);\n  fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10, 10,\t\t\t// T_ASMINUS, T_ASSTAR, T_ASSLASH,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110\t\t\t// T_STAR, T_SLASH\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_SLASH)\n    fatals(\"Token with no precedence in op_precedence:\", Tstring[tokentype]);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (prec);\n}\n\n// prefix_expression: postfix_expression\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstatic struct ASTnode *prefix(int ptp) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Prevent '&' being performed on an array\n    if (tree->sym->stype == S_ARRAY)\n      fatal(\"& operator cannot be performed on an array\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Ensure the tree's type is a pointer\n    if (!ptrtype(tree->type))\n      fatal(\"* operator must be followed by an expression of pointer type\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree =\n      mkastunary(A_DEREF, value_at(tree->type), tree->ctype, tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this if needed to int so that it's signed\n    tree->rvalue = 1;\n    if (tree->type == P_CHAR)\n      tree->type = P_INT;\n    tree = mkastunary(A_NEGATE, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  default:\n    tree = postfix(ptp);\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix(ptp);\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp = binexpr(0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. XXX We should also\n      // consider the third expression's type.\n      return (mkastnode\n\t      (A_TERNARY, right->type, right->ctype, left, right, ltemp,\n\t       NULL, 0));\n\n    case A_ASSIGN:\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, left->ctype, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n      break;\n\n    default:\n      // We are not doing a ternary or assignment, so both trees should\n      // be rvalues. Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, right->ctype, ASTop);\n      rtemp = modify_type(right, left->type, left->ctype, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left->ctype, left, NULL,\n\t\tright, NULL, 0);\n\n    // Some operators produce an int result regardless of their operands\n    switch (binastop(tokentype)) {\n    case A_LOGOR:\n    case A_LOGAND:\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      left->type = P_INT;\n    }\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs(reg);\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    if (c->left)\n      genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs(NOREG);\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for an\n// A_LOGAND or A_LOGOR operation\nstatic int gen_logandor(struct ASTnode *n) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n  int reg;\n\n  // Generate the code for the left expression\n  // followed by the jump to the false label\n  reg= genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(NOREG);\n\n  // Generate the code for the right expression\n  // followed by the jump to the false label\n  reg= genAST(n->right, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(reg);\n\n  // We didn't jump so set the right boolean value\n  if (n->op== A_LOGAND) {\n    cgloadboolean(reg, 1);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 0);\n  } else {\n    cgloadboolean(reg, 0);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 1);\n  }\n  cglabel(Lend);\n  return(reg);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // Save the registers before we copy the arguments\n  spill_all_regs();\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg= NOREG, rightreg= NOREG;\n\n  // Empty tree, do nothing\n  if (n==NULL) return(NOREG);\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_TERNARY:\n      return (gen_ternary(n));\n    case A_LOGOR:\n      return (gen_logandor(n));\n    case A_LOGAND:\n      return (gen_logandor(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL)\n\tgenAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs(NOREG);\n      if (n->right != NULL)\n\tgenAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs(NOREG);\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdiv(leftreg, rightreg));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF, A_WHILE or A_TERNARY,\n      // generate a compare followed by a jump. Otherwise, compare\n      // registers and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE ||\n\t  parentASTop == A_TERNARY)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->a_intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->a_intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tif (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC\n\t    || n->sym->class == C_EXTERN) {\n\t  return (cgloadglob(n->sym, n->op));\n\t} else {\n\t  return (cgloadlocal(n->sym, n->op));\n\t}\n      } else\n\treturn (NOREG);\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n\tcase A_ASPLUS:\n\t  leftreg = cgadd(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASMINUS:\n\t  leftreg = cgsub(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSTAR:\n\t  leftreg = cgmul(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSLASH:\n\t  leftreg = cgdiv(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL ||\n\t      n->right->sym->class == C_STATIC)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->a_size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      if (n->sym->class == C_GLOBAL || n->sym->class == C_STATIC)\n\treturn (cgloadglob(n->sym, n->op));\n      else\n\treturn (cgloadlocal(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      if (n->left->sym->class == C_GLOBAL || n->left->sym->class == C_STATIC)\n\treturn (cgloadglob(n->left->sym, n->op));\n      else\n\treturn (cgloadlocal(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (leftreg);\t\t// Not much to do\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs(int keepreg) {\n  freeall_registers(keepreg);\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\n\n// Generate a global string.\n// If append is true, append to\n// previous genglobstr() call.\nint genglobstr(char *strvalue, int append) {\n  int l = genlabel();\n  cgglobstr(l, strvalue, append);\n  return (l);\n}\nvoid genglobstrend(void) {\n  cgglobstrend();\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\nint toupper(int c);\nint tolower(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "57_Mop_up_pt3/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n\nint * __errno_location(void);\n\n#define errno (* __errno_location())\n\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "57_Mop_up_pt3/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "57_Mop_up_pt3/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "57_Mop_up_pt3/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n#ifndef EOF\n# define EOF (-1)\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint sprintf(char *str, char *format);\nint snprintf(char *str, size_t size, char *format);\nint fgetc(FILE *stream);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\nFILE *popen(char *command, char *type);\nint pclose(FILE *stream);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "57_Mop_up_pt3/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\nint system(char *command);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "57_Mop_up_pt3/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\nint strcmp(char *s1, char *s2);\nint strncmp(char *s1, char *s2, size_t n);\nchar *strerror(int errnum);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "57_Mop_up_pt3/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "57_Mop_up_pt3/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix;\n  posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Linestart = 1;\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token = 0;\t\t// and set there is no lookahead token\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n\n  // Dump the symbol table if requested\n  if (O_dumpsym) {\n    printf(\"Symbols for %s\\n\", filename);\n    dumpsymtables();\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char **objlist) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcSTM] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -M dump the symbol table for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char *argv[]) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_dumpsym = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'M':\n\t  O_dumpsym = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  int i;\n  for (i = 0; s[i] != '\\0'; i++)\n    if (s[i] == (char) c)\n      return (i);\n  return (-1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (Linestart && c == '#') {\t// We've hit a pre-processor statement\n    Linestart = 0;\t\t// No longer at the start of the line\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n\n  Linestart = 0;\t\t// No longer at the start of the line\n  if ('\\n' == c) {\n    Line++;\t\t\t// Increment line count\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return (n);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn (hexchar());\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = (char)c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = (char)c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, NULL, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, NULL, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, NULL, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree= NULL;\n\n  // Ensure we have 'return'\n  match(T_RETURN, \"return\");\n\n  // See if we have a return value\n  if (Token.token == T_LPAREN) {\n    // Can't return a value if function returns P_VOID\n    if (Functionid->type == P_VOID)\n      fatal(\"Can't return from a void function\");\n\n    // Skip the left parenthesis\n    lparen();\n\n    // Parse the following expression\n    tree = binexpr(0);\n\n    // Ensure this is compatible with the function's type\n    tree = modify_type(tree, Functionid->type, Functionid->ctype, 0);\n    if (tree == NULL)\n      fatal(\"Incompatible type to return\");\n\n    // Get the ')'\n    rparen();\n  }\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, NULL, tree, NULL, 0);\n\n  // Get the ';'\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, P_NONE, NULL, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, P_NONE, NULL, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *body, *n, *c;\n  struct ASTnode *casetree = NULL, *casetail;\n  int inloop = 1, casecount = 0;\n  int seendefault = 0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left = binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n = mkastunary(A_SWITCH, P_NONE, NULL, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch (Token.token) {\n\t// Leave the loop when we hit a '}'\n      case T_RBRACE:\n\tif (casecount == 0)\n\t  fatal(\"No cases in switch\");\n\tinloop = 0;\n\tbreak;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token == T_DEFAULT) {\n\t  ASTop = A_DEFAULT;\n\t  seendefault = 1;\n\t  scan(&Token);\n\t} else {\n\t  ASTop = A_CASE;\n\t  scan(&Token);\n\t  left = binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue = left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n\t  // that there isn't a duplicate case value\n\t  for (c = casetree; c != NULL; c = c->right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n\t}\n\n\t// Scan the ':' and increment the casecount\n\tmatch(T_COLON, \":\");\n\tcasecount++;\n\n\t// If the next token is a T_CASE, the existing case will fall\n\t// into the next case. Otherwise, parse the case body.\n\tif (Token.token == T_CASE)\n\t  body = NULL;\n\telse\n\t  body = compound_statement(1);\n\n\t// Build a sub-tree with any compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree == NULL) {\n\t  casetree = casetail =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t} else {\n\t  casetail->right =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t  casetail = casetail->right;\n\t}\n\tbreak;\n      default:\n\tfatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue = casecount;\n  n->right = casetree;\n  rbrace();\n\n  return (n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_SEMI:\n      // An empty statement\n      semi();\n      break;\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return (stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt = binexpr(0);\n\tsemi();\n\treturn (stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt = binexpr(0);\n      semi();\n      return (stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Leave if we've hit the end token. We do this first to allow\n    // an empty compound statement\n    if (Token.token == T_RBRACE)\n      return (left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT))\n      return (left);\n\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, NULL, left, NULL, tree, NULL, 0);\n    }\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list,\n\t\t\t\t      int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class == 0 || class == list->class)\n\treturn (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead = Globtail = NULL;\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Membhead = Membtail = NULL;\n  Structhead = Structtail = NULL;\n  Unionhead = Uniontail = NULL;\n  Enumhead = Enumtail = NULL;\n  Typehead = Typetail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev = NULL;\n\n  // Walk the global table looking for static entries\n  for (g = Globhead; g != NULL; g = g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL)\n\tprev->next = g->next;\n      else\n\tGlobhead->next = g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n\tif (prev != NULL)\n\t  Globtail = prev;\n\telse\n\t  Globtail = Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev = g;\n}\n\n// Dump a single symbol\nstatic void dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n    case P_VOID:\n      printf(\"void \");\n      break;\n    case P_CHAR:\n      printf(\"char \");\n      break;\n    case P_INT:\n      printf(\"int \");\n      break;\n    case P_LONG:\n      printf(\"long \");\n      break;\n    case P_STRUCT:\n      if (sym->ctype != NULL)\n\tprintf(\"struct %s \", sym->ctype->name);\n      else\n\tprintf(\"struct %s \", sym->name);\n      break;\n    case P_UNION:\n      if (sym->ctype != NULL)\n\tprintf(\"union %s \", sym->ctype->name);\n      else\n\tprintf(\"union %s \", sym->name);\n      break;\n    default:\n      printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++)\n    printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      break;\n    case S_FUNCTION:\n      printf(\"()\");\n      break;\n    case S_ARRAY:\n      printf(\"[]\");\n      break;\n    default:\n      printf(\" unknown stype\");\n  }\n\n  switch (sym->class) {\n    case C_GLOBAL:\n      printf(\": global\");\n      break;\n    case C_LOCAL:\n      printf(\": local\");\n      break;\n    case C_PARAM:\n      printf(\": param\");\n      break;\n    case C_EXTERN:\n      printf(\": extern\");\n      break;\n    case C_STATIC:\n      printf(\": static\");\n      break;\n    case C_STRUCT:\n      printf(\": struct\");\n      break;\n    case C_UNION:\n      printf(\": union\");\n      break;\n    case C_MEMBER:\n      printf(\": member\");\n      break;\n    case C_ENUMTYPE:\n      printf(\": enumtype\");\n      break;\n    case C_ENUMVAL:\n      printf(\": enumval\");\n      break;\n    case C_TYPEDEF:\n      printf(\": typedef\");\n      break;\n    default:\n      printf(\": unknown class\");\n  }\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      if (sym->class == C_ENUMVAL)\n\tprintf(\", value %d\\n\", sym->st_posn);\n      else\n\tprintf(\", size %d\\n\", sym->size);\n      break;\n    case S_FUNCTION:\n      printf(\", %d params\\n\", sym->nelems);\n      break;\n    case S_ARRAY:\n      printf(\", %d elems, size %d\\n\", sym->nelems, sym->size);\n      break;\n  }\n\n  switch (sym->type & (~0xf)) {\n    case P_STRUCT:\n    case P_UNION:\n      dumptable(sym->member, NULL, 4);\n  }\n\n  switch (sym->stype) {\n    case S_FUNCTION:\n      dumptable(sym->member, NULL, 4);\n  }\n}\n\n// Dump one symbol table\nvoid dumptable(struct symtable *head, char *name, int indent) {\n  struct symtable *sym;\n\n  if (head != NULL && name != NULL)\n    printf(\"%s\\n--------\\n\", name);\n  for (sym = head; sym != NULL; sym = sym->next)\n    dumpsym(sym, indent);\n}\n\nvoid dumpsymtables(void) {\n  dumptable(Globhead, \"Global\", 0);\n  printf(\"\\n\");\n  dumptable(Enumhead, \"Enums\", 0);\n  printf(\"\\n\");\n  dumptable(Typehead, \"Typedefs\", 0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input032.c",
    "content": "Unknown variable or function:pizza on line 4 of input032.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input042.c",
    "content": "Unknown variable or function:fred on line 3 of input042.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input043.c",
    "content": "Unknown variable or function:b on line 3 of input043.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input044.c",
    "content": "Unknown variable or function:z on line 3 of input044.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input046.c",
    "content": "* operator must be followed by an expression of pointer type on line 3 of input046.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input059.c",
    "content": "Unknown variable or function:y on line 3 of input059.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input060.c",
    "content": "Expression is not a struct/union on line 3 of input060.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input061.c",
    "content": "Expression is not a pointer to a struct/union on line 3 of input061.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input093.c",
    "content": "Unknown variable or function:fred on line 1 of input093.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input124.c",
    "content": "Cannot ++ on rvalue on line 6 of input124.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input126.c",
    "content": "Unknown variable or function:ptr on line 7 of input126.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input129.c",
    "content": "Cannot ++ and/or -- more than once on line 6 of input129.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input141.c",
    "content": "Declaration of array parameters is not implemented on line 4 of input141.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/err.input142.c",
    "content": "Array must have non-zero elements:fred on line 1 of input142.c\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input122.c",
    "content": "#include <stdio.h>\n\nint x, y, z1, z2;\n\nint main() {\n  for (x= 0; x <= 1; x++) {\n    for (y= 0; y <= 1; y++) {\n      z1= x || y; z2= x && y;\n      printf(\"x %d, y %d, x || y %d, x && y %d\\n\", x, y, z1, z2);\n    }\n  }\n  \n  //z= x || y;\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input123.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  for (x=0; x < 20; x++)\n    switch(x) {\n      case 2:\n      case 3:\n      case 5:\n      case 7:\n      case 11: printf(\"%2d infant prime\\n\", x); break;\n      case 13:\n      case 17:\n      case 19: printf(\"%2d teen   prime\\n\", x); break;\n      case 0:\n      case 1:\n      case 4:\n      case 6:\n      case 8:\n      case 9:\n      case 10:\n      case 12: printf(\"%2d infant composite\\n\", x); break;\n      default: printf(\"%2d teen   composite\\n\", x); break;\n    }\n\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input124.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary++;\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input125.c",
    "content": "#include <stdio.h>\n\nint ary[5];\nint *ptr;\nint x;\n\nint main() {\n  ary[3]= 2008;\n  ptr= ary;\t\t\t// Load ary's address into ptr\n  x= ary[3]; printf(\"%d\\n\", x);\n  x= ptr[3]; printf(\"%d\\n\", x); // Treat ptr as an array\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input126.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary[3]= 2008;\n  ptr= &ary;\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input127.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nvoid fred(int *ptr) {\t\t// Receive a pointer\n  printf(\"%d\\n\", ptr[3]);\n}\n\nint main() {\n  ary[3]= 2008;\n  printf(\"%d\\n\", ary[3]);\n  fred(ary);\t\t\t// Pass ary as a pointer\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input128.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int val;\n  struct foo *next;\n};\n\nstruct foo head, mid, tail;\n\nint main() {\n  struct foo *ptr;\n  tail.val= 20; tail.next= NULL;\n  mid.val= 15; mid.next= &tail;\n  head.val= 10; head.next= &mid;\n\n  ptr= &head;\n  printf(\"%d %d\\n\", head.val, ptr->val);\n  printf(\"%d %d\\n\", mid.val, ptr->next->val);\n  printf(\"%d %d\\n\", tail.val, ptr->next->next->val);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input129.c",
    "content": "#include <stdio.h>\n\nint x= 6;\n\nint main() {\n  printf(\"%d\\n\", x++ ++);\n  return(0);\n}\n\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input130.c",
    "content": "#include <stdio.h>\n\nchar *x= \"foo\";\n\nint main() {\n  printf(\"Hello \" \"world\" \"\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input131.c",
    "content": "#include <stdio.h>\n\nvoid donothing() { }\n\nint main() {\n  int x=0;\n  printf(\"Doing nothing... \"); donothing();\n  printf(\"nothing done\\n\");\n\n  while (++x < 100) ;\n  printf(\"x is now %d\\n\", x);\n\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input132.c",
    "content": "extern int fred;\nint fred;\n\nint mary;\nextern int mary;\n\nint main() { return(0); }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input133.c",
    "content": "#include <stdio.h>\n\nextern int fred[];\nint fred[23];\n\nchar mary[100];\nextern char mary[];\n\nvoid main() { printf(\"OK\\n\"); }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input134.c",
    "content": "#include <stdio.h>\n\nchar y = 'a';\nchar *x;\n\nint main() {\n  x= &y;        if (x && y == 'a') printf(\"1st match\\n\");\n  x= NULL;      if (x && y == 'a') printf(\"2nd match\\n\");\n  x= &y; y='b'; if (x && y == 'a') printf(\"3rd match\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input135.c",
    "content": "#include <stdio.h>\n\nvoid fred() {\n  int x= 5;\n  printf(\"testing x\\n\");\n  if (x > 4) return;\n  printf(\"x below 5\\n\");\n}\n\nint main() {\n  fred();\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input136.c",
    "content": "#include <stdio.h>\n\nint add(int x, int y) {\n  return(x+y);\n}\n\nint main() {\n  int result;\n  result= 3 * add(2,3) - 5 * add(4,6);\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input137.c",
    "content": "#include <stdio.h>\n\nint a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8;\n\nint main() {\n  int x;\n  x= ((((((a + b) + c) + d) + e) + f) + g) + h;\n  x= a + (b + (c + (d + (e + (f + (g + h))))));\n  printf(\"x is %d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input138.c",
    "content": "#include <stdio.h>\n\nint x, y, z;\n\nint a=1;\nint *aptr;\n\nint main() {\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x && y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x || y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // Now some lazy evaluation\n  aptr= NULL;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  aptr= &a;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input139.c",
    "content": "#include <stdio.h>\n\nint same(int x) { return(x); }\n\nint main() {\n  int a= 3;\n\n  if (same(a) && same(a) >= same(a))\n    printf(\"same apparently\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input140.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int  i;\n  int  ary[5];\n  char z;\n\n  // Write below the array\n  z= 'H';\n\n  // Fill the array\n  for (i=0; i < 5; i++)\n    ary[i]= i * i;\n\n  // Write above the array\n  i=14;\n\n  // Print out the array\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", ary[i]);\n\n  // See if either side is OK\n  printf(\"%d %c\\n\", i, z);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input141.c",
    "content": "static int fred[5];\nint jim;\n\nint foo(int mary[6]) { return(5); }\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input142.c",
    "content": "static int fred[];\nint jim;\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input143.c",
    "content": "#include <stdio.h>\n\nchar foo;\nchar *a, *b, *c;\n\nint main() {\n\n  a= b= c= NULL;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  a= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  b= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  c= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  else\n    printf(\"All  three  are non-NULL\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input144.c",
    "content": "#include <stdio.h>\n#include <errno.h>\n#include <string.h>\nchar *filename= \"fred\";\nint main() {\n    fprintf(stdout, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/input145.c",
    "content": "#include <stdio.h>\n\nchar *str= \"qwertyuiop\";\n\nint list[]= {3, 5, 7, 9, 11, 13, 15};\n\nint *lptr;\n\nint main() {\n  printf(\"%c\\n\", *str);\n  str= str + 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str -= 1; printf(\"%c\\n\", *str);\n\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  return(0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/nasmext.inc",
    "content": "extern\tprintint\nextern\tprintchar\nextern\topen\nextern\tclose\nextern\tread\nextern\twrite\nextern\tprintf\nextern\tfprintf\nextern\tstdout\nextern\tstrerror\nextern\t__errno_location\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input122.c",
    "content": "x 0, y 0, x || y 0, x && y 0\nx 0, y 1, x || y 1, x && y 0\nx 1, y 0, x || y 1, x && y 0\nx 1, y 1, x || y 1, x && y 1\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input123.c",
    "content": " 0 infant composite\n 1 infant composite\n 2 infant prime\n 3 infant prime\n 4 infant composite\n 5 infant prime\n 6 infant composite\n 7 infant prime\n 8 infant composite\n 9 infant composite\n10 infant composite\n11 infant prime\n12 infant composite\n13 teen   prime\n14 teen   composite\n15 teen   composite\n16 teen   composite\n17 teen   prime\n18 teen   composite\n19 teen   prime\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input125.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input127.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input128.c",
    "content": "10 10\n15 15\n20 20\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input130.c",
    "content": "Hello world\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input131.c",
    "content": "Doing nothing... nothing done\nx is now 100\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input132.c",
    "content": ""
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input133.c",
    "content": "OK\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input134.c",
    "content": "1st match\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input135.c",
    "content": "testing x\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input136.c",
    "content": "-35\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input137.c",
    "content": "x is 36\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input138.c",
    "content": "0 0 | 0\n0 1 | 0\n1 0 | 0\n1 1 | 1\n0 0 | 0\n0 1 | 1\n1 0 | 1\n1 1 | 1\naptr is NULL or doesn't point at 1\naptr points at 1\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input139.c",
    "content": "same apparently\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input140.c",
    "content": "0\n1\n4\n9\n16\n5 H\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input143.c",
    "content": "One of the three is NULL\nOne of the three is NULL\nOne of the three is NULL\nAll  three  are non-NULL\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input144.c",
    "content": "Unable to open fred: Success\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/out.input145.c",
    "content": "q\nw\ne\nr\ne\n3\n5\n7\n9\n7\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "57_Mop_up_pt3/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "57_Mop_up_pt3/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->ctype = ctype;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n  int i;\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    case A_TOBOOL:\n      fprintf(stdout, \"A_TOBOOL\\n\");\n      return;\n    case A_LOGOR:\n      fprintf(stdout, \"A_LOGOR\\n\");\n      return;\n    case A_LOGAND:\n      fprintf(stdout, \"A_LOGAND\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "57_Mop_up_pt3/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n\t\t\t    struct symtable *rctype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // For A_LOGOR and A_LOGAND, both types have to be int or pointer types\n  if (op==A_LOGOR || op==A_LOGAND) {\n    if (!inttype(ltype) && !ptrtype(ltype))\n      return(NULL);\n    if (!inttype(ltype) && !ptrtype(rtype))\n      return(NULL);\n    return (tree);\n  }\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, NULL, tree, NULL, 0));\n  }\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return (tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n  // We can scale only on add and subtract operations\n  if (op == A_ADD || op == A_SUBTRACT ||\n      op == A_ASPLUS || op == A_ASMINUS) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, rctype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h incdir.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\nincdir.h:\n\techo \"#define INCDIR \\\"$(INCDIR)\\\"\" > incdir.h\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwjarm compn *.o *.s out a.out incdir.h\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n"
  },
  {
    "path": "58_Ptr_Increments/Readme.md",
    "content": "# Part 58: Fixing Pointer Increments/Decrements\n\nIn the last part of our compiler writing journey, I mentioned that there\nwas a problem with pointer increments and decrements. Let's see what the\nproblem is and how I fixed it.\n\nWe saw with the AST operations A_ADD, A_SUBTRACT, A_ASPLUS and A_ASMINUS\nwhere one operand is a pointer and the other is an integer type, we need\nto scale the integer value by the size of the type that the pointer\npoints at. In `modify_type()` in `types.c`:\n\n```c\n  // We can scale only on add and subtract operations\n  if (op == A_ADD || op == A_SUBTRACT ||\n      op == A_ASPLUS || op == A_ASMINUS) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n        return (mkastunary(A_SCALE, rtype, rctype, tree, NULL, rsize));\n      else\n        return (tree);          // Size 1, no need to scale\n    }\n  }\n```\n\nBut this scaling doesn't occur when we use `++` or `--`, either as\npreincrement/decrement or postincrement/decrement operators. Here,\nwe simply strap an A_PREINC, A_PREDEC, A_POSTINC or A_POSTDEC AST node\nto the AST tree that we are operating on, and then leave it to the code generator\nto deal with the situation.\n\nUp to now, this got resolved when we call either `cgloadglob()` or\n`cgloadlocal()` in `cg.c` to load the value of a global or local variable.\nFor example:\n\n```c\nint cgloadglob(struct symtable *sym, int op) {\n  ...\n  if (cgprimsize(sym->type) == 8) {\n    if (op == A_PREINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n    ...\n    fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\n    if (op == A_POSTINC)\n      fprintf(Outfile, \"\\tincq\\t%s(%%rip)\\n\", sym->name);\n  }\n  ...\n}\n```\n\nNote, however, that the `incq` increments by one. That's fine if the\nvariable we are incrementing is of integer type, but it fails to deal\nwith variables that are of pointer type.\n\nAs well, the functions `cgloadglob()` and `cgloadlocal()` are very similar.\nThey differ in what instructions we use to access the variable: is it\nat a fixed location, or a location relative to the stack frame.\n\n## Fixing the Problem\n\nFor a while I thought I could get the parser to build an AST tree similar\nto the one that `modify_type()` does, but I gave up on that. Thank goodness.\nI decided that, as `++` and `--` are already being done in `cgloadglob()`,\nthat I should attack the problem here.\n\nHalfway through, I realised that I could merge `cgloadglob()` and\n`cgloadlocal()` into a single function. Let's look at the solution\nin stages.\n\n```c\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadvar(struct symtable *sym, int op) {\n  int r, postreg, offset=1;\n\n  // Get a new register\n  r = alloc_register();\n\n  // If the symbol is a pointer, use the size\n  // of the type that it points to as any\n  // increment or decrement. If not, it's one.\n  if (ptrtype(sym->type))\n    offset= typesize(value_at(sym->type), sym->ctype);\n```\n\nWe start by assuming that we will be doing +1 as an increment. However,\nonce we realise that we could be incrementing a pointer, we change\nthis to the the size of the type that it points to.\n\n```c\n  // Negate the offset for decrements\n  if (op==A_PREDEC || op==A_POSTDEC)\n    offset= -offset;\n```\n\nNow the `offset` is negative if we are going to do a decrement.\n\n```c\n  // If we have a pre-operation\n  if (op==A_PREINC || op==A_PREDEC) {\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    else\n      fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n```\n\nThis is where our algorithm differs from the old code. The old code used\nthe `incq` instruction, but that limits the variable change to exactly one.\nNow that we have the variable's address in our register...\n\n```c\n    // and change the value at that address\n    switch (sym->size) {\n      case 1: fprintf(Outfile, \"\\taddb\\t$%d,(%s)\\n\", offset, reglist[r]); break;\n      case 4: fprintf(Outfile, \"\\taddl\\t$%d,(%s)\\n\", offset, reglist[r]); break;\n      case 8: fprintf(Outfile, \"\\taddq\\t$%d,(%s)\\n\", offset, reglist[r]); break;\n    }\n  }\n```\n\nwe can add the offset on to the variable, using the register as a pointer\nto the variable. We have to use different instructions based on the size\nof the variable.\n\nWe've done any pre-increment or pre-decrement operation. Now we can load\nthe variable's value into a register:\n\n```c\n  // Now load the output register with the value\n  if (sym->class == C_LOCAL || sym->class == C_PARAM) {\n    switch (sym->size) {\n      case 1: fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]); break;\n      case 4: fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]); break;\n      case 8: fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    }\n  } else {\n    switch (sym->size) {\n      case 1: fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]); break;\n      case 4: fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]); break;\n      case 8: fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    }\n  }\n```\n\nDepending on if the symbol is local, or global,\nwe load from a named location or from an location relative to the\nframe pointer. We choose an instruction to zero pad the result\nbased on the symbol's size.\n\nThe value is safely in register `r`. But now we need to do any post-increment\nor post-decrement. We can re-use the pre-op code, but we'll need a new\nregister:\n\n```c\n  // If we have a post-operation, get a new register\n  if (op==A_POSTINC || op==A_POSTDEC) {\n    postreg = alloc_register();\n\n    // Same code as before, but using postreg\n\n    // and free the register\n    free_register(postreg);\n  }\n\n  // Return the register with the value\n  return(r);\n}\n```\n\nSo the code for `cgloadvar()` is about as complex as the old code, but\nit now deals with pointer increments. The `tests/input145.c` test program\nverifies that this new code works:\n\n```c\nint list[]= {3, 5, 7, 9, 11, 13, 15};\nint *lptr;\n\nint main() {\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  lptr++   ; printf(\"%d\\n\", *lptr);\n  lptr--   ; printf(\"%d\\n\", *lptr);\n  ++lptr   ; printf(\"%d\\n\", *lptr);\n  --lptr   ; printf(\"%d\\n\", *lptr);\n}\n```\n\n## How Did I Miss Modulo?\n\nWith this fixed, I went back to feeding the compiler source code to itself\nand found, to my amazement, that the modulo operators `%` and `%=` were\nmissing. I have no idea why I hadn't put them in before.\n\n### New Tokens and AST Operators\n\nAdding new operators to the compiler now is tricky because we have to\nsynchronise changes in several places. Let's see where. In `defs.h`\nwe need to add the tokens:\n\n```c\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH, T_ASMOD,\n  T_QUESTION, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH, T_MOD,\n  ...\n};\n```\n\nwith T_ASMOD and T_MOD the new tokens. Now we need to create AST ops to match:\n\n```c\n // AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR,                  //  1\n  A_ASSLASH, A_ASMOD, A_TERNARY, A_LOGOR,                       //  5\n  A_LOGAND, A_OR, A_XOR, A_AND, A_EQ, A_NE, A_LT,               //  9\n  A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,                         // 16\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_MOD,               // 21\n  ...\n};\n```\n\nNow we need to add the scanner changes to scan these tokens. I won't show\nthe code, but I will show the change to the table of token strings in\n`scan.c`:\n\n```c\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\", \"%=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"%\",\n  ...\n};\n```\n\n### Operator Precedence\n\nNow we need to set the operators' precedence in `expr.c`. T_SLASH used to\nbe the highest operator but it's been replaced with T_MOD:\n\n```c\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_MOD)\n    return (tokentype);\n  fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (0);                   // Keep -Wall happy\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,                    // T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10,                       // T_ASMINUS, T_ASSTAR,\n  10, 10,                       // T_ASSLASH, T_ASMOD,\n  15,                           // T_QUESTION,\n  20, 30,                       // T_LOGOR, T_LOGAND\n  40, 50, 60,                   // T_OR, T_XOR, T_AMPER \n  70, 70,                       // T_EQ, T_NE\n  80, 80, 80, 80,               // T_LT, T_GT, T_LE, T_GE\n  90, 90,                       // T_LSHIFT, T_RSHIFT\n  100, 100,                     // T_PLUS, T_MINUS\n  110, 110, 110                 // T_STAR, T_SLASH, T_MOD\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_MOD)\n    fatals(\"Token with no precedence in op_precedence:\", Tstring[tokentype]);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (prec);\n}\n```\n\n### Code Generation\n\nWe already have a `cgdiv()` function to generate the x86-64 instructions\nto do division. Looking at the manual for the `idiv` instruction:\n\n> idivq S: signed divide `%rdx:%rax` by S. The quotient is\n  stored in `%rax`. The remainder is stored in `%rdx`.\n\nSo we can modify `cgdiv()` to take the AST operation being performed,\nand it can do both division and remainder (modulo). The new function\nin `cg.c` is:\n\n```c\n// Divide or modulo the first register by the second and\n// return the number of the register with the result\nint cgdivmod(int r1, int r2, int op) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  if (op== A_DIVIDE)\n    fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  else\n    fprintf(Outfile, \"\\tmovq\\t%%rdx,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n```\n\nThe `tests/input147.c` confirms that the above changes work:\n\n```c\n#include <stdio.h>\n\nint a;\n\nint main() {\n  printf(\"%d\\n\", 24 % 9);\n  printf(\"%d\\n\", 31 % 11);\n  a= 24; a %= 9; printf(\"%d\\n\",a);\n  a= 31; a %= 11; printf(\"%d\\n\",a);\n  return(0);\n}\n```\n\n## Why Doesn't It Link\n\nWe are now at the point where our compiler can parse each and every of its\nown source code files. But when I try to link them, I get a warning about\nmissing `L0` labels.\n\nAfter a bit of investigation, it turns out that I wasn't properly\npropagating the end label for loops and switches in `genIF()` in `gen.c`.\nThe fix is on line 49:\n\n```c\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  ...\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n  ...\n}\n```\n\nNow that `loopendlabel` is being propagated, I can do this (in a shell\nscript I call `memake`):\n\n```\n#!/bin/sh\nmake install\n\nrm *.s *.o\n\nfor i in cg.c decl.c expr.c gen.c main.c misc.c \\\n        opt.c scan.c stmt.c sym.c tree.c types.c\ndo echo \"./cwj -c $i\"; ./cwj -c $i ; ./cwj -S $i\ndone\n\ncc -o cwj0 cg.o decl.o expr.o gen.o main.o misc.o \\\n        opt.o scan.o stmt.o sym.o tree.o types.o\n```\n\nWe end up with a binary, `cwj0`, which is the result of the compiler\ncompiling itself.\n\n```\n$ size cwj0\n   text    data     bss     dec     hex filename\n 106540    3008      48  109596   1ac1c cwj0\n\n$ file cwj0\ncwj0: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically\n      linked, interpreter /lib64/l, for GNU/Linux 3.2.0, not stripped\n```\n\n## Conclusion and What's Next\n\nFor the pointer increment problem, I definitely had to scratch my head quite\na lot and look at several possible alternate solutions. I did get halfway\nthrough trying to build a new AST tree with an A_SCALE in it. Then I tossed it\nall away and went for the change in `cgloadvar()`. That's much nicer.\n\nThe modulo operators were simple to add (in theory), but annoyingly\ndifficult to get everything synchronised (in practice). There is probably\nsome scope to refactor here to make the synchronisation much easier.\n\nThen, while trying to link all the object files that our compiler had\nmade from its own source code, I found that we were not propagating\nloop/switch end labels properly.\n\nWe've now reached the point where our compiler can parse every one of\nits source code files, generate assembly code for them, and we can link them.\nWe have reached the final stage of our journey, one that is probably\ngoing to be the most painful, the **WDIW** stage: why doesn't it work?\n\nHere, we don't have a debugger, we are going to have to look at lots\nof assembly output. We'll have to single-step assembly and look at\nregister values.\n\nIn the next part of our compiler writing journey, I will start on the\n**WDIW** stage. We are going to need some strategies to make our work\neffective. [Next step](../59_WDIW_pt1/Readme.md)\n"
  },
  {
    "path": "58_Ptr_Increments/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n\tfatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpopq\\t%s\\n\", reglist[r]);\n}\n\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  fprintf(Outfile, \"# freeing all registers\\n\");\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg=0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      fprintf(Outfile, \"# allocated register %s\\n\", reglist[reg]);\n      return (reg);\n    }\n  }\n\n  // We have no registers, so we must spill one\n  reg= (spillreg % NUMFREEREGS);\n  spillreg++;\n  fprintf(Outfile, \"# spilling reg %s\\n\", reglist[reg]);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0) {\n    fprintf(Outfile, \"# error trying to free register %s\\n\", reglist[reg]);\n    fatald(\"Error trying to free register\", reg);\n  }\n\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg= (spillreg % NUMFREEREGS);\n    fprintf(Outfile, \"# unspilling reg %s\\n\", reglist[reg]);\n    popreg(reg);\n  } else {\n    fprintf(Outfile, \"# freeing reg %s\\n\", reglist[reg]);\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid spill_all_regs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void unspill_all_regs(void) {\n  int i;\n\n  for (i = NUMFREEREGS - 1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"__switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"__next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     __no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"__no:\\n\"\n\t  \"        loop    __next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\" \"\\t.type\\t%s, @function\\n\", name, name);\n  fprintf(Outfile, \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\" \"\\tmovq\\t%%rsp, %%rbp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->size);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n  freeall_registers(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadvar(struct symtable *sym, int op) {\n  int r, postreg, offset=1;\n\n  // Get a new register\n  r = alloc_register();\n\n  // If the symbol is a pointer, use the size\n  // of the type that it points to as any\n  // increment or decrement. If not, it's one.\n  if (ptrtype(sym->type))\n    offset= typesize(value_at(sym->type), sym->ctype);\n\n  // Negate the offset for decrements\n  if (op==A_PREDEC || op==A_POSTDEC)\n    offset= -offset;\n\n  // If we have a pre-operation\n  if (op==A_PREINC || op==A_PREDEC) {\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    else\n      fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\n    // and change the value at that address\n    switch (sym->size) {\n      case 1: fprintf(Outfile, \"\\taddb\\t$%d,(%s)\\n\", offset, reglist[r]); break;\n      case 4: fprintf(Outfile, \"\\taddl\\t$%d,(%s)\\n\", offset, reglist[r]); break;\n      case 8: fprintf(Outfile, \"\\taddq\\t$%d,(%s)\\n\", offset, reglist[r]); break;\n    }\n  }\n\n  // Now load the output register with the value\n  if (sym->class == C_LOCAL || sym->class == C_PARAM) {\n    switch (sym->size) {\n      case 1: fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]); break;\n      case 4: fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]); break;\n      case 8: fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    }\n  } else {\n    switch (sym->size) {\n      case 1: fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]); break;\n      case 4: fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]); break;\n      case 8: fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    }\n  }\n\n  // If we have a post-operation, get a new register\n  if (op==A_POSTINC || op==A_POSTDEC) {\n    postreg = alloc_register();\n\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[postreg]);\n    else\n      fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[postreg]);\n    // and change the value at that address\n\n    switch (sym->size) {\n      case 1: fprintf(Outfile, \"\\taddb\\t$%d,(%s)\\n\", offset, reglist[postreg]); break;\n      case 4: fprintf(Outfile, \"\\taddl\\t$%d,(%s)\\n\", offset, reglist[postreg]); break;\n      case 8: fprintf(Outfile, \"\\taddq\\t$%d,(%s)\\n\", offset, reglist[postreg]); break;\n    }\n    // and free the register\n    free_register(postreg);\n  }\n\n  // Return the register with the value\n  return(r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Divide or modulo the first register by the second and\n// return the number of the register with the result\nint cgdivmod(int r1, int r2, int op) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  if (op== A_DIVIDE)\n    fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  else\n    fprintf(Outfile, \"\\tmovq\\t%%rdx,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", val, reglist[r]);\n}\n\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch(op) {\n    case A_IF:\n    case A_WHILE:\n    case A_LOGAND:\n      fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n      break;\n    case A_LOGOR:\n      fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n      break;\n    default:\n      fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n      fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n\n  // Unspill all the registers\n  unspill_all_regs();\n\n  // Get a new register and copy the return value into it\n  outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n  free_register(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r],\n\t\tsym->st_posn);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r],\n\t\tsym->st_posn);\n\tbreak;\n      default:\n\tfatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n      case 1:\n\tfprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n\tbreak;\n      case 8:\n\t// Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n\tif (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t    && initvalue != 0)\n\t  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n\telse\n\t  fprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n\tbreak;\n      default:\n\tfor (i = 0; i < size; i++)\n\t  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n        case P_CHAR:\n\t  fprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n\t  break;\n        case P_INT:\n\t  fprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n\t  break;\n        case P_LONG:\n\t  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n\t  break;\n        default:\n\t  fatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovl\\t%s, (%s)\\n\", dreglist[r1], reglist[r2]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\t__switch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nint newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[]  = { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n\"rdi\"  };\nstatic char *breglist[]  = { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n\"dil\"  };\nstatic char *dreglist[]  = { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n\"esi\", \"edi\"  };\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpop\\t%s\\n\", reglist[r]);\n}\n\n// Set all registers as available\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  fprintf(Outfile, \"; freeing all registers\\n\");\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg=0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      fprintf(Outfile, \"; allocated register %s\\n\", reglist[reg]);\n      return (reg);\n    }\n  }\n  // We have no registers, so we must spill one\n  reg = (spillreg % NUMFREEREGS);\n  spillreg++;\n  fprintf(Outfile, \"; spilling reg %s\\n\", reglist[reg]);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0) {\n    fprintf(Outfile, \"# error trying to free register %s\\n\", reglist[reg]);\n    fatald(\"Error trying to free register\", reg);\n  }\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg= (spillreg % NUMFREEREGS);\n    fprintf(Outfile, \"; unspilling reg %s\\n\", reglist[reg]);\n    popreg(reg);\n  } else {\n    fprintf(Outfile, \"; freeing reg %s\\n\", reglist[reg]);\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid spill_all_regs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void unspill_all_regs(void) {\n  int i;\n\n  for (i = NUMFREEREGS - 1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"__switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"__next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    __no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"__no:\\n\"\n\t  \"        loop   __next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\" \"\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", name);\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->size);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n  freeall_registers(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadvar(struct symtable *sym, int op) {\n  int r, postreg, offset = 1;\n\n  // Get a new register\n  r = alloc_register();\n\n  // If the symbol is a pointer, use the size\n  // of the type that it points to as any\n  // increment or decrement. If not, it's one.\n  if (ptrtype(sym->type))\n    offset= typesize(value_at(sym->type), sym->ctype);\n\n  // Negate the offset for decrements\n  if (op==A_PREDEC || op==A_POSTDEC)\n    offset= -offset;\n\n  // If we have a pre-operation\n  if (op==A_PREINC || op==A_PREDEC) {\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r], sym->st_posn);\n    else\n      fprintf(Outfile, \"\\tlea\\t%s, [%s]\\n\", reglist[r], sym->name);\n\n    // and change the value at that address\n    switch (sym->size) {\n      case 1: fprintf(Outfile, \"\\tadd\\tbyte [%s], %d\\n\", reglist[r], offset); break;\n      case 4: fprintf(Outfile, \"\\tadd\\tdword [%s], %d\\n\", reglist[r], offset); break;\n      case 8: fprintf(Outfile, \"\\tadd\\tqword [%s], %d\\n\", reglist[r], offset); break;\n    }\n  }\n\n  // Now load the output register with the value\n  if (sym->class == C_LOCAL || sym->class == C_PARAM) {\n    switch (sym->size) {\n      case 1: fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], sym->st_posn); break;\n      case 4: fprintf(Outfile, \"\\tmovsxd\\t%s, dword [rbp+%d]\\n\", reglist[r], sym->st_posn); break;\n      case 8: fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r], sym->st_posn);\n    }\n  } else {\n    switch (sym->size) {\n      case 1: fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], sym->name); break;\n      case 4: fprintf(Outfile, \"\\tmovsxd\\t%s, dword [%s]\\n\", reglist[r], sym->name); break;\n      case 8: fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    }\n  }\n\n  // If we have a post-operation, get a new register\n  if (op==A_POSTINC || op==A_POSTDEC) {\n    postreg = alloc_register();\n\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[postreg], sym->st_posn);\n    else\n      fprintf(Outfile, \"\\tlea\\t%s, [%s]\\n\", reglist[postreg], sym->name);\n    // and change the value at that address\n\n    switch (sym->size) {\n      case 1: fprintf(Outfile, \"\\tadd\\tbyte [%s], %d\\n\", reglist[postreg], offset); break;\n      case 4: fprintf(Outfile, \"\\tadd\\tdword [%s], %d\\n\", reglist[postreg], offset); break;\n      case 8: fprintf(Outfile, \"\\tadd\\tqword [%s], %d\\n\", reglist[postreg], offset); break;\n    }\n    // and free the register\n    free_register(postreg);\n  }\n\n  // Return the register with the value\n  return(r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Divide or modulo the first register by the second and\n// return the number of the register with the result\nint cgdivmod(int r1, int r2, int op) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  if (op == A_DIVIDE)\n    fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  else\n    fprintf(Outfile, \"\\tmov\\t%s, rdx\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], val);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch(op) {\n    case A_IF:\n    case A_WHILE:\n    case A_LOGAND:\n      fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n      break;\n    case A_LOGOR:\n      fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n      break;\n    default:\n      fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // Unspill all the registers\n  unspill_all_regs();\n  // Get a new register and copy the return value into it\n  outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n  free_register(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n        /* compact version using times instead of loop\n        fprintf(Outfile, \"\\ttimes\\t%d\\tdb\\t0\\n\", size);\n        */\n    }\n  }\n\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n        case P_CHAR:\n          fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n          break;\n        case P_INT:\n          fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n          break;\n        case P_LONG:\n          fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n          break;\n        default:\n          fatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmov\\t[%s], dword %s\\n\", reglist[r2], dreglist[r1]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\t__switch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Linestart;\t\t     \t// True if at start of a line\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\nextern char *Tstring[];\t\t\t// List of token strings\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_dumpsym;\t\t// If true, dump the symbol table\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "58_Ptr_Increments/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Get the type inside the parentheses\n  type = parse_stars(parse_type(ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return (type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree = optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type = tree->type;\n    tree = tree->left;\n  }\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return (tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue == 0)\n      return (0);\n  }\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return (tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a pointer to a symbol that may already exist\n// return true if this symbol doesn't exist. We use\n// this function to convert externs into globals\nint is_new_symbol(struct symtable *sym, int class, \n\t\t  int type, struct symtable *ctype) {\n\n  // There is no existing symbol, thus is new\n  if (sym==NULL) return(1);\n\n  // global versus extern: if they match that it's not new\n  // and we can convert the class to global\n  if ((sym->class== C_GLOBAL && class== C_EXTERN)\n      || (sym->class== C_EXTERN && class== C_GLOBAL)) {\n\n      // If the types don't match, there's a problem\n      if (type != sym->type)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // Struct/unions, also compare the ctype\n      if (type >= P_STRUCT && ctype != sym->ctype)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // If we get to here, the types match, so mark the symbol\n      // as global\n      sym->class= C_GLOBAL;\n      // Return that symbol is not new\n      return(0);\n  }\n\n  // It must be a duplicate symbol if we get here\n  fatals(\"Duplicate global variable declaration\", sym->name);\n  return(-1);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree = NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, type, ctype))\n        sym = addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym = addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym = addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist = (int *) malloc(sizeof(int));\n      sym->initlist[0] = parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym->ctype, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, varnode->ctype, 0);\n      if (exprnode == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode->ctype, exprnode,\n\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t\t// New symbol table entry\n  int nelems = -1;\t\t// Assume the number of elements won't be given\n  int maxelems;\t\t\t// The maximum number of elements in the init list\n  int *initlist;\t\t// The list of initial elements \n  int i = 0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems = parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, pointer_to(type), ctype))\n        sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class, 0, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, pointer_to(type), ctype, S_ARRAY, 0);\n      break;\n    default:\n      fatal(\"Declaration of array parameters is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems = nelems;\n    else\n      maxelems = TABLE_INCREMENT;\n    initlist = (int *) malloc(maxelems * sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n\tfatal(\"Too many values in initialisation list\");\n\n      initlist[i++] = parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n\tmaxelems += TABLE_INCREMENT;\n\tinitlist = (int *) realloc(initlist, maxelems * sizeof(int));\n      }\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n\tscan(&Token);\n\tbreak;\n      }\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j = i; j < sym->nelems; j++)\n      initlist[j] = 0;\n    if (i > nelems)\n      nelems = i;\n    sym->initlist = initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  // Only externs can have no elements.\n  if (class != C_EXTERN && nelems<=0)\n    fatals(\"Array must have non-zero elements\", sym->name);\n\n  sym->nelems = nelems;\n  sym->size = sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n\tparamcnt = 0;\n\tscan(&Token);\n\tbreak;\n      }\n    }\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, ctype, tree, oldfuncsym, endlabel);\n\n  // Do optimisations on the AST tree\n  tree = optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t = declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t == -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead == NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name = NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET) {\n    sym = array_declaration(varname, type, ctype, class);\n    *tree= NULL;\t// Local arrays are not initialised\n  } else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree = NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n\tfatal(\"Function definition not at global level\");\n      return (type);\n    }\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree == NULL)\n      *gluetree = tree;\n    else\n      *gluetree =\n\tmkastnode(A_GLUE, P_NONE, NULL, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n  return(0);\t// Keep -Wall happy\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype= NULL;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "58_Ptr_Increments/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int level);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue, int append);\nvoid genglobstrend(void);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nint alloc_register(void);\nvoid freeall_registers(int keepreg);\nvoid spill_all_regs(void);\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadvar(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdivmod(int r1, int r2, int op);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue, int append);\nvoid cgglobstrend(void);\nint cgcompare_and_set(int ASTop, int r1, int r2);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nvoid cgloadboolean(int r, int val);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\nvoid dumptable(struct symtable *head, char *name, int indent);\nvoid dumpsymtables(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(struct symtable **ctype);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n                            struct symtable *rctype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "58_Ptr_Increments/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n#include \"incdir.h\"\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -f elf64 -w-ptr -pnasmext.inc -o \"\n#define LDCMD \"cc -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -o \"\n#define LDCMD \"cc -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH, T_ASMOD,\n  T_QUESTION, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH, T_MOD,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR,\t\t\t//  1\n  A_ASSLASH, A_ASMOD, A_TERNARY, A_LOGOR,\t\t\t//  5\n  A_LOGAND, A_OR, A_XOR, A_AND, A_EQ, A_NE, A_LT,\t\t//  9\n  A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\t\t\t\t// 16\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_MOD,\t\t// 21\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\t\t\t\t// 26\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\t\t\t// 30\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\t\t\t\t// 35\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\t\t\t// 39\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\t\t// 43\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\t\t// 48\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "58_Ptr_Increments/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree =\n      mkastnode(A_GLUE, P_NONE, NULL, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree =\n    mkastunary(A_FUNCCALL, funcptr->type, funcptr->ctype, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(struct ASTnode *left) {\n  struct ASTnode *right;\n\n  // Check that the sub-tree is a pointer\n  if (!ptrtype(left->type))\n    fatal(\"Not an array or pointer\");\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, left->ctype, A_ADD);\n\n  // Return an AST tree where the array's base has the offset added to it,\n  // and dereference the element. Still an lvalue at this point.\n  left =\n    mkastnode(A_ADD, left->type, left->ctype, left, NULL, right, NULL, 0);\n  left =\n    mkastunary(A_DEREF, value_at(left->type), left->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(struct ASTnode *left, int withpointer) {\n  struct ASTnode *right;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the left AST tree is a pointer to struct or union\n  if (withpointer && left->type != pointer_to(P_STRUCT)\n      && left->type != pointer_to(P_UNION))\n    fatal(\"Expression is not a pointer to a struct/union\");\n\n  // Or, check that the left AST tree is a struct or union.\n  // If so, change it from an A_IDENT to an A_ADDR so that\n  // we get the base address, not the value at this address.\n  if (!withpointer) {\n    if (left->type == P_STRUCT || left->type == P_UNION)\n      left->op = A_ADDR;\n    else\n      fatal(\"Expression is not a struct/union\");\n  }\n\n  // Get the details of the composite type\n  typeptr = left->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left =\n    mkastnode(A_ADD, pointer_to(m->type), m->ctype, left, NULL, right, NULL,\n\t      0);\n  left = mkastunary(A_DEREF, m->type, m->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse a parenthesised expression and\n// return an AST node representing it.\nstatic struct ASTnode *paren_expression(int ptp) {\n  struct ASTnode *n;\n  int type = 0;\n  struct symtable *ctype = NULL;\n\n  // Beginning of a parenthesised expression, skip the '('.\n  scan(&Token);\n\n  // If the token after is a type identifier, this is a cast expression\n  switch (Token.token) {\n  case T_IDENT:\n    // We have to see if the identifier matches a typedef.\n    // If not, treat it as an expression.\n    if (findtypedef(Text) == NULL) {\n      n = binexpr(0);\t// ptp is zero as expression inside ( )\n      break;\n    }\n  case T_VOID:\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n  case T_STRUCT:\n  case T_UNION:\n  case T_ENUM:\n    // Get the type inside the parentheses\n    type = parse_cast(&ctype);\n\n    // Skip the closing ')' and then parse the following expression\n    rparen();\n\n  default:\n    n = binexpr(ptp);\t\t// Scan in the expression. We pass in ptp\n\t\t\t\t// as the cast doesn't change the\n\t\t\t\t// expression's precedence\n  }\n\n  // We now have at least an expression in n, and possibly a non-zero type\n  // in type if there was a cast. Skip the closing ')' if there was no cast.\n  if (type == 0)\n    rparen();\n  else\n    // Otherwise, make a unary AST node for the cast\n    n = mkastunary(A_CAST, type, ctype, n, NULL, 0);\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(int ptp) {\n  struct ASTnode *n;\n  struct symtable *enumptr;\n  struct symtable *varptr;\n  int id;\n  int type = 0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type = parse_stars(parse_type(&ctype, &class));\n\n    // Get the type's size\n    size = typesize(type, ctype);\n    rparen();\n\n    // Make a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    id = genglobstr(Text, 0);\n\n    // For successive STRLIT tokens, append their contents\n    // to this one\n    while (1) {\n      scan(&Peektoken);\n      if (Peektoken.token != T_STRLIT) break;\n      genglobstr(Text, 1);\n      scan(&Token);\t// To skip it properly\n    }\n\n    // Now make a leaf AST node for it. id is the string's label.\n    genglobstrend();\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, NULL, id);\n    break;\n\n  case T_IDENT:\n    // If the identifier matches an enum value,\n    // return an A_INTLIT node\n    if ((enumptr = findenumval(Text)) != NULL) {\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, enumptr->st_posn);\n      break;\n    }\n    // See if this identifier exists as a symbol. For arrays, set rvalue to 1.\n    if ((varptr = findsymbol(Text)) == NULL)\n      fatals(\"Unknown variable or function\", Text);\n    switch (varptr->stype) {\n    case S_VARIABLE:\n      n = mkastleaf(A_IDENT, varptr->type, varptr->ctype, varptr, 0);\n      break;\n    case S_ARRAY:\n      n = mkastleaf(A_ADDR, varptr->type, varptr->ctype, varptr, 0);\n      n->rvalue = 1;\n      break;\n    case S_FUNCTION:\n      // Function call, see if the next token is a left parenthesis\n      scan(&Token);\n      if (Token.token != T_LPAREN)\n\tfatals(\"Function name used without parentheses\", Text);\n      return (funccall());\n    default:\n      fatals(\"Identifier not a scalar or array variable\", Text);\n    }\n    break;\n\n  case T_LPAREN:\n    return (paren_expression(ptp));\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(int ptp) {\n  struct ASTnode *n;\n\n  // Get the primary expression\n  n = primary(ptp);\n\n  // Loop until there are no more postfix operators\n  while (1) {\n    switch (Token.token) {\n    case T_LBRACKET:\n      // An array reference\n      n = array_access(n);\n      break;\n\n    case T_DOT:\n      // Access into a struct or union\n      n = member_access(n, 0);\n      break;\n\n    case T_ARROW:\n      // Pointer access into a struct or union\n      n = member_access(n, 1);\n      break;\n\n    case T_INC:\n      // Post-increment: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot ++ on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTINC;\n      break;\n\n    case T_DEC:\n      // Post-decrement: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot -- on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTDEC;\n      break;\n\n    default:\n      return (n);\n    }\n  }\n\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_MOD)\n    return (tokentype);\n  fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10,\t\t\t// T_ASMINUS, T_ASSTAR,\n  10, 10,\t\t\t// T_ASSLASH, T_ASMOD,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110, 110\t\t\t// T_STAR, T_SLASH, T_MOD\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_MOD)\n    fatals(\"Token with no precedence in op_precedence:\", Tstring[tokentype]);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (prec);\n}\n\n// prefix_expression: postfix_expression\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstatic struct ASTnode *prefix(int ptp) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Prevent '&' being performed on an array\n    if (tree->sym->stype == S_ARRAY)\n      fatal(\"& operator cannot be performed on an array\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Ensure the tree's type is a pointer\n    if (!ptrtype(tree->type))\n      fatal(\"* operator must be followed by an expression of pointer type\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree =\n      mkastunary(A_DEREF, value_at(tree->type), tree->ctype, tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this if needed to int so that it's signed\n    tree->rvalue = 1;\n    if (tree->type == P_CHAR)\n      tree->type = P_INT;\n    tree = mkastunary(A_NEGATE, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  default:\n    tree = postfix(ptp);\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix(ptp);\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp = binexpr(0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. XXX We should also\n      // consider the third expression's type.\n      return (mkastnode\n\t      (A_TERNARY, right->type, right->ctype, left, right, ltemp,\n\t       NULL, 0));\n\n    case A_ASSIGN:\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, left->ctype, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n      break;\n\n    default:\n      // We are not doing a ternary or assignment, so both trees should\n      // be rvalues. Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, right->ctype, ASTop);\n      rtemp = modify_type(right, left->type, left->ctype, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left->ctype, left, NULL,\n\t\tright, NULL, 0);\n\n    // Some operators produce an int result regardless of their operands\n    switch (binastop(tokentype)) {\n    case A_LOGOR:\n    case A_LOGAND:\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      left->type = P_INT;\n    }\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs(reg);\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    if (c->left)\n      genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs(NOREG);\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for an\n// A_LOGAND or A_LOGOR operation\nstatic int gen_logandor(struct ASTnode *n) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n  int reg;\n\n  // Generate the code for the left expression\n  // followed by the jump to the false label\n  reg= genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(NOREG);\n\n  // Generate the code for the right expression\n  // followed by the jump to the false label\n  reg= genAST(n->right, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(reg);\n\n  // We didn't jump so set the right boolean value\n  if (n->op== A_LOGAND) {\n    cgloadboolean(reg, 1);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 0);\n  } else {\n    cgloadboolean(reg, 0);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 1);\n  }\n  cglabel(Lend);\n  return(reg);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // Save the registers before we copy the arguments\n  spill_all_regs();\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg= NOREG, rightreg= NOREG;\n\n  // Empty tree, do nothing\n  if (n==NULL) return(NOREG);\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_TERNARY:\n      return (gen_ternary(n));\n    case A_LOGOR:\n      return (gen_logandor(n));\n    case A_LOGAND:\n      return (gen_logandor(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // registers after each child\n      if (n->left != NULL)\n\tgenAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs(NOREG);\n      if (n->right != NULL)\n\tgenAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      genfreeregs(NOREG);\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg));\n    case A_DIVIDE:\n      return (cgdivmod(leftreg, rightreg, A_DIVIDE));\n    case A_MOD:\n      return (cgdivmod(leftreg, rightreg, A_MOD));\n    case A_AND:\n      return (cgand(leftreg, rightreg));\n    case A_OR:\n      return (cgor(leftreg, rightreg));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF, A_WHILE or A_TERNARY,\n      // generate a compare followed by a jump. Otherwise, compare\n      // registers and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE ||\n\t  parentASTop == A_TERNARY)\n\treturn (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel));\n      else\n\treturn (cgcompare_and_set(n->op, leftreg, rightreg));\n    case A_INTLIT:\n      return (cgloadint(n->a_intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->a_intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\treturn (cgloadvar(n->sym, n->op));\n      } else\n\treturn (NOREG);\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASMOD:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n\tcase A_ASPLUS:\n\t  leftreg = cgadd(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASMINUS:\n\t  leftreg = cgsub(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSTAR:\n\t  leftreg = cgmul(leftreg, rightreg);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSLASH:\n\t  leftreg = cgdivmod(leftreg, rightreg, A_DIVIDE);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASMOD:\n\t  leftreg = cgdivmod(leftreg, rightreg, A_MOD);\n\t  n->right = n->left;\n\t  break;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL ||\n\t      n->right->sym->class == C_STATIC)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, n->left->type, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      return (cgaddress(n->sym));\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, n->left->type));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3));\n\tdefault:\n\t  // Load a register with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->a_size, P_INT);\n\t  return (cgmul(leftreg, rightreg));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      return (cgloadvar(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      return (cgloadvar(n->left->sym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg));\n    case A_INVERT:\n      return (cginvert(leftreg));\n    case A_LOGNOT:\n      return (cglognot(leftreg));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (leftreg);\t\t// Not much to do\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs(int keepreg) {\n  freeall_registers(keepreg);\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\n\n// Generate a global string.\n// If append is true, append to\n// previous genglobstr() call.\nint genglobstr(char *strvalue, int append) {\n  int l = genlabel();\n  cgglobstr(l, strvalue, append);\n  return (l);\n}\nvoid genglobstrend(void) {\n  cgglobstrend();\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "58_Ptr_Increments/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\nint toupper(int c);\nint tolower(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "58_Ptr_Increments/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n\nint * __errno_location(void);\n\n#define errno (* __errno_location())\n\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "58_Ptr_Increments/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "58_Ptr_Increments/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "58_Ptr_Increments/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n#ifndef EOF\n# define EOF (-1)\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint sprintf(char *str, char *format);\nint snprintf(char *str, size_t size, char *format);\nint fgetc(FILE *stream);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\nFILE *popen(char *command, char *type);\nint pclose(FILE *stream);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "58_Ptr_Increments/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\nint system(char *command);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "58_Ptr_Increments/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\nint strcmp(char *s1, char *s2);\nint strncmp(char *s1, char *s2, size_t n);\nchar *strerror(int errnum);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "58_Ptr_Increments/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "58_Ptr_Increments/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix;\n  posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Linestart = 1;\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token = 0;\t\t// and set there is no lookahead token\n  genpreamble();\t\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n\n  // Dump the symbol table if requested\n  if (O_dumpsym) {\n    printf(\"Symbols for %s\\n\", filename);\n    dumpsymtables();\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char **objlist) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcSTM] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -M dump the symbol table for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char **argv) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, j, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_dumpsym = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'M':\n\t  O_dumpsym = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  int i;\n  for (i = 0; s[i] != '\\0'; i++)\n    if (s[i] == (char) c)\n      return (i);\n  return (-1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (Linestart && c == '#') {\t// We've hit a pre-processor statement\n    Linestart = 0;\t\t// No longer at the start of the line\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n\n  Linestart = 0;\t\t// No longer at the start of the line\n  if ('\\n' == c) {\n    Line++;\t\t\t// Increment line count\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return (n);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn (hexchar());\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = (char)c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = (char)c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\", \"%=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"%\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case '%':\n      if ((c = next()) == '=') {\n\tt->token = T_ASMOD;\n      } else {\n\tputback(c);\n\tt->token = T_MOD;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, NULL, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, NULL, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, NULL, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree= NULL;\n\n  // Ensure we have 'return'\n  match(T_RETURN, \"return\");\n\n  // See if we have a return value\n  if (Token.token == T_LPAREN) {\n    // Can't return a value if function returns P_VOID\n    if (Functionid->type == P_VOID)\n      fatal(\"Can't return from a void function\");\n\n    // Skip the left parenthesis\n    lparen();\n\n    // Parse the following expression\n    tree = binexpr(0);\n\n    // Ensure this is compatible with the function's type\n    tree = modify_type(tree, Functionid->type, Functionid->ctype, 0);\n    if (tree == NULL)\n      fatal(\"Incompatible type to return\");\n\n    // Get the ')'\n    rparen();\n  }\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, NULL, tree, NULL, 0);\n\n  // Get the ';'\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, P_NONE, NULL, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, P_NONE, NULL, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *body, *n, *c;\n  struct ASTnode *casetree = NULL, *casetail;\n  int inloop = 1, casecount = 0;\n  int seendefault = 0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left = binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n = mkastunary(A_SWITCH, P_NONE, NULL, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch (Token.token) {\n\t// Leave the loop when we hit a '}'\n      case T_RBRACE:\n\tif (casecount == 0)\n\t  fatal(\"No cases in switch\");\n\tinloop = 0;\n\tbreak;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token == T_DEFAULT) {\n\t  ASTop = A_DEFAULT;\n\t  seendefault = 1;\n\t  scan(&Token);\n\t} else {\n\t  ASTop = A_CASE;\n\t  scan(&Token);\n\t  left = binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue = left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n\t  // that there isn't a duplicate case value\n\t  for (c = casetree; c != NULL; c = c->right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n\t}\n\n\t// Scan the ':' and increment the casecount\n\tmatch(T_COLON, \":\");\n\tcasecount++;\n\n\t// If the next token is a T_CASE, the existing case will fall\n\t// into the next case. Otherwise, parse the case body.\n\tif (Token.token == T_CASE)\n\t  body = NULL;\n\telse\n\t  body = compound_statement(1);\n\n\t// Build a sub-tree with any compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree == NULL) {\n\t  casetree = casetail =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t} else {\n\t  casetail->right =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t  casetail = casetail->right;\n\t}\n\tbreak;\n      default:\n\tfatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue = casecount;\n  n->right = casetree;\n  rbrace();\n\n  return (n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_SEMI:\n      // An empty statement\n      semi();\n      break;\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      rbrace();\n      return (stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt = binexpr(0);\n\tsemi();\n\treturn (stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      return (if_statement());\n    case T_WHILE:\n      return (while_statement());\n    case T_FOR:\n      return (for_statement());\n    case T_RETURN:\n      return (return_statement());\n    case T_BREAK:\n      return (break_statement());\n    case T_CONTINUE:\n      return (continue_statement());\n    case T_SWITCH:\n      return (switch_statement());\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt = binexpr(0);\n      semi();\n      return (stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Leave if we've hit the end token. We do this first to allow\n    // an empty compound statement\n    if (Token.token == T_RBRACE)\n      return (left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT))\n      return (left);\n\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, NULL, left, NULL, tree, NULL, 0);\n    }\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n"
  },
  {
    "path": "58_Ptr_Increments/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list,\n\t\t\t\t      int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class == 0 || class == list->class)\n\treturn (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead = Globtail = NULL;\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Membhead = Membtail = NULL;\n  Structhead = Structtail = NULL;\n  Unionhead = Uniontail = NULL;\n  Enumhead = Enumtail = NULL;\n  Typehead = Typetail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev = NULL;\n\n  // Walk the global table looking for static entries\n  for (g = Globhead; g != NULL; g = g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL)\n\tprev->next = g->next;\n      else\n\tGlobhead->next = g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n\tif (prev != NULL)\n\t  Globtail = prev;\n\telse\n\t  Globtail = Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev = g;\n}\n\n// Dump a single symbol\nstatic void dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n    case P_VOID:\n      printf(\"void \");\n      break;\n    case P_CHAR:\n      printf(\"char \");\n      break;\n    case P_INT:\n      printf(\"int \");\n      break;\n    case P_LONG:\n      printf(\"long \");\n      break;\n    case P_STRUCT:\n      if (sym->ctype != NULL)\n\tprintf(\"struct %s \", sym->ctype->name);\n      else\n\tprintf(\"struct %s \", sym->name);\n      break;\n    case P_UNION:\n      if (sym->ctype != NULL)\n\tprintf(\"union %s \", sym->ctype->name);\n      else\n\tprintf(\"union %s \", sym->name);\n      break;\n    default:\n      printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++)\n    printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      break;\n    case S_FUNCTION:\n      printf(\"()\");\n      break;\n    case S_ARRAY:\n      printf(\"[]\");\n      break;\n    default:\n      printf(\" unknown stype\");\n  }\n\n  switch (sym->class) {\n    case C_GLOBAL:\n      printf(\": global\");\n      break;\n    case C_LOCAL:\n      printf(\": local\");\n      break;\n    case C_PARAM:\n      printf(\": param\");\n      break;\n    case C_EXTERN:\n      printf(\": extern\");\n      break;\n    case C_STATIC:\n      printf(\": static\");\n      break;\n    case C_STRUCT:\n      printf(\": struct\");\n      break;\n    case C_UNION:\n      printf(\": union\");\n      break;\n    case C_MEMBER:\n      printf(\": member\");\n      break;\n    case C_ENUMTYPE:\n      printf(\": enumtype\");\n      break;\n    case C_ENUMVAL:\n      printf(\": enumval\");\n      break;\n    case C_TYPEDEF:\n      printf(\": typedef\");\n      break;\n    default:\n      printf(\": unknown class\");\n  }\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      if (sym->class == C_ENUMVAL)\n\tprintf(\", value %d\\n\", sym->st_posn);\n      else\n\tprintf(\", size %d\\n\", sym->size);\n      break;\n    case S_FUNCTION:\n      printf(\", %d params\\n\", sym->nelems);\n      break;\n    case S_ARRAY:\n      printf(\", %d elems, size %d\\n\", sym->nelems, sym->size);\n      break;\n  }\n\n  switch (sym->type & (~0xf)) {\n    case P_STRUCT:\n    case P_UNION:\n      dumptable(sym->member, NULL, 4);\n  }\n\n  switch (sym->stype) {\n    case S_FUNCTION:\n      dumptable(sym->member, NULL, 4);\n  }\n}\n\n// Dump one symbol table\nvoid dumptable(struct symtable *head, char *name, int indent) {\n  struct symtable *sym;\n\n  if (head != NULL && name != NULL)\n    printf(\"%s\\n--------\\n\", name);\n  for (sym = head; sym != NULL; sym = sym->next)\n    dumpsym(sym, indent);\n}\n\nvoid dumpsymtables(void) {\n  dumptable(Globhead, \"Global\", 0);\n  printf(\"\\n\");\n  dumptable(Enumhead, \"Enums\", 0);\n  printf(\"\\n\");\n  dumptable(Typehead, \"Typedefs\", 0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input032.c",
    "content": "Unknown variable or function:pizza on line 4 of input032.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input042.c",
    "content": "Unknown variable or function:fred on line 3 of input042.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input043.c",
    "content": "Unknown variable or function:b on line 3 of input043.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input044.c",
    "content": "Unknown variable or function:z on line 3 of input044.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input046.c",
    "content": "* operator must be followed by an expression of pointer type on line 3 of input046.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input059.c",
    "content": "Unknown variable or function:y on line 3 of input059.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input060.c",
    "content": "Expression is not a struct/union on line 3 of input060.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input061.c",
    "content": "Expression is not a pointer to a struct/union on line 3 of input061.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input093.c",
    "content": "Unknown variable or function:fred on line 1 of input093.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input124.c",
    "content": "Cannot ++ on rvalue on line 6 of input124.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input126.c",
    "content": "Unknown variable or function:ptr on line 7 of input126.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input129.c",
    "content": "Cannot ++ and/or -- more than once on line 6 of input129.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input141.c",
    "content": "Declaration of array parameters is not implemented on line 4 of input141.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/err.input142.c",
    "content": "Array must have non-zero elements:fred on line 1 of input142.c\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input122.c",
    "content": "#include <stdio.h>\n\nint x, y, z1, z2;\n\nint main() {\n  for (x= 0; x <= 1; x++) {\n    for (y= 0; y <= 1; y++) {\n      z1= x || y; z2= x && y;\n      printf(\"x %d, y %d, x || y %d, x && y %d\\n\", x, y, z1, z2);\n    }\n  }\n  \n  //z= x || y;\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input123.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  for (x=0; x < 20; x++)\n    switch(x) {\n      case 2:\n      case 3:\n      case 5:\n      case 7:\n      case 11: printf(\"%2d infant prime\\n\", x); break;\n      case 13:\n      case 17:\n      case 19: printf(\"%2d teen   prime\\n\", x); break;\n      case 0:\n      case 1:\n      case 4:\n      case 6:\n      case 8:\n      case 9:\n      case 10:\n      case 12: printf(\"%2d infant composite\\n\", x); break;\n      default: printf(\"%2d teen   composite\\n\", x); break;\n    }\n\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input124.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary++;\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input125.c",
    "content": "#include <stdio.h>\n\nint ary[5];\nint *ptr;\nint x;\n\nint main() {\n  ary[3]= 2008;\n  ptr= ary;\t\t\t// Load ary's address into ptr\n  x= ary[3]; printf(\"%d\\n\", x);\n  x= ptr[3]; printf(\"%d\\n\", x); // Treat ptr as an array\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input126.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary[3]= 2008;\n  ptr= &ary;\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input127.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nvoid fred(int *ptr) {\t\t// Receive a pointer\n  printf(\"%d\\n\", ptr[3]);\n}\n\nint main() {\n  ary[3]= 2008;\n  printf(\"%d\\n\", ary[3]);\n  fred(ary);\t\t\t// Pass ary as a pointer\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input128.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int val;\n  struct foo *next;\n};\n\nstruct foo head, mid, tail;\n\nint main() {\n  struct foo *ptr;\n  tail.val= 20; tail.next= NULL;\n  mid.val= 15; mid.next= &tail;\n  head.val= 10; head.next= &mid;\n\n  ptr= &head;\n  printf(\"%d %d\\n\", head.val, ptr->val);\n  printf(\"%d %d\\n\", mid.val, ptr->next->val);\n  printf(\"%d %d\\n\", tail.val, ptr->next->next->val);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input129.c",
    "content": "#include <stdio.h>\n\nint x= 6;\n\nint main() {\n  printf(\"%d\\n\", x++ ++);\n  return(0);\n}\n\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input130.c",
    "content": "#include <stdio.h>\n\nchar *x= \"foo\";\n\nint main() {\n  printf(\"Hello \" \"world\" \"\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input131.c",
    "content": "#include <stdio.h>\n\nvoid donothing() { }\n\nint main() {\n  int x=0;\n  printf(\"Doing nothing... \"); donothing();\n  printf(\"nothing done\\n\");\n\n  while (++x < 100) ;\n  printf(\"x is now %d\\n\", x);\n\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input132.c",
    "content": "extern int fred;\nint fred;\n\nint mary;\nextern int mary;\n\nint main() { return(0); }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input133.c",
    "content": "#include <stdio.h>\n\nextern int fred[];\nint fred[23];\n\nchar mary[100];\nextern char mary[];\n\nvoid main() { printf(\"OK\\n\"); }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input134.c",
    "content": "#include <stdio.h>\n\nchar y = 'a';\nchar *x;\n\nint main() {\n  x= &y;        if (x && y == 'a') printf(\"1st match\\n\");\n  x= NULL;      if (x && y == 'a') printf(\"2nd match\\n\");\n  x= &y; y='b'; if (x && y == 'a') printf(\"3rd match\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input135.c",
    "content": "#include <stdio.h>\n\nvoid fred() {\n  int x= 5;\n  printf(\"testing x\\n\");\n  if (x > 4) return;\n  printf(\"x below 5\\n\");\n}\n\nint main() {\n  fred();\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input136.c",
    "content": "#include <stdio.h>\n\nint add(int x, int y) {\n  return(x+y);\n}\n\nint main() {\n  int result;\n  result= 3 * add(2,3) - 5 * add(4,6);\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input137.c",
    "content": "#include <stdio.h>\n\nint a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8;\n\nint main() {\n  int x;\n  x= ((((((a + b) + c) + d) + e) + f) + g) + h;\n  x= a + (b + (c + (d + (e + (f + (g + h))))));\n  printf(\"x is %d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input138.c",
    "content": "#include <stdio.h>\n\nint x, y, z;\n\nint a=1;\nint *aptr;\n\nint main() {\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x && y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x || y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // Now some lazy evaluation\n  aptr= NULL;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  aptr= &a;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input139.c",
    "content": "#include <stdio.h>\n\nint same(int x) { return(x); }\n\nint main() {\n  int a= 3;\n\n  if (same(a) && same(a) >= same(a))\n    printf(\"same apparently\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input140.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int  i;\n  int  ary[5];\n  char z;\n\n  // Write below the array\n  z= 'H';\n\n  // Fill the array\n  for (i=0; i < 5; i++)\n    ary[i]= i * i;\n\n  // Write above the array\n  i=14;\n\n  // Print out the array\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", ary[i]);\n\n  // See if either side is OK\n  printf(\"%d %c\\n\", i, z);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input141.c",
    "content": "static int fred[5];\nint jim;\n\nint foo(int mary[6]) { return(5); }\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input142.c",
    "content": "static int fred[];\nint jim;\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input143.c",
    "content": "#include <stdio.h>\n\nchar foo;\nchar *a, *b, *c;\n\nint main() {\n\n  a= b= c= NULL;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  a= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  b= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  c= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  else\n    printf(\"All  three  are non-NULL\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input144.c",
    "content": "#include <stdio.h>\n#include <errno.h>\n#include <string.h>\nchar *filename= \"fred\";\nint main() {\n    fprintf(stdout, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input145.c",
    "content": "#include <stdio.h>\n\nchar *str= \"qwertyuiop\";\n\nint list[]= {3, 5, 7, 9, 11, 13, 15};\n\nint *lptr;\n\nint main() {\n  printf(\"%c\\n\", *str);\n  str= str + 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str -= 1; printf(\"%c\\n\", *str);\n\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input146.c",
    "content": "#include <stdio.h>\n\nchar *str= \"qwertyuiop\";\n\nint list[]= {3, 5, 7, 9, 11, 13, 15};\n\nint *lptr;\n\nint main() {\n  printf(\"%c\\n\", *str);\n  str= str + 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str -= 1; printf(\"%c\\n\", *str);\n  str++; printf(\"%c\\n\", *str);\n  str--; printf(\"%c\\n\", *str);\n  ++str; printf(\"%c\\n\", *str);\n  --str; printf(\"%c\\n\\n\", *str);\n\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  lptr++   ; printf(\"%d\\n\", *lptr);\n  lptr--   ; printf(\"%d\\n\", *lptr);\n  ++lptr   ; printf(\"%d\\n\", *lptr);\n  --lptr   ; printf(\"%d\\n\", *lptr);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/input147.c",
    "content": "#include <stdio.h>\n\nint a;\n\nint main() {\n  printf(\"%d\\n\", 24 % 9);\n  printf(\"%d\\n\", 31 % 11);\n  a= 24; a %= 9; printf(\"%d\\n\",a);\n  a= 31; a %= 11; printf(\"%d\\n\",a);\n  return(0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "58_Ptr_Increments/tests/nasmext.inc",
    "content": "extern\tprintint\nextern\tprintchar\nextern\topen\nextern\tclose\nextern\tread\nextern\twrite\nextern\tprintf\nextern\tfprintf\nextern\tstdout\nextern\tstrerror\nextern\t__errno_location\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "58_Ptr_Increments/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input122.c",
    "content": "x 0, y 0, x || y 0, x && y 0\nx 0, y 1, x || y 1, x && y 0\nx 1, y 0, x || y 1, x && y 0\nx 1, y 1, x || y 1, x && y 1\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input123.c",
    "content": " 0 infant composite\n 1 infant composite\n 2 infant prime\n 3 infant prime\n 4 infant composite\n 5 infant prime\n 6 infant composite\n 7 infant prime\n 8 infant composite\n 9 infant composite\n10 infant composite\n11 infant prime\n12 infant composite\n13 teen   prime\n14 teen   composite\n15 teen   composite\n16 teen   composite\n17 teen   prime\n18 teen   composite\n19 teen   prime\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input125.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input127.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input128.c",
    "content": "10 10\n15 15\n20 20\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input130.c",
    "content": "Hello world\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input131.c",
    "content": "Doing nothing... nothing done\nx is now 100\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input132.c",
    "content": ""
  },
  {
    "path": "58_Ptr_Increments/tests/out.input133.c",
    "content": "OK\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input134.c",
    "content": "1st match\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input135.c",
    "content": "testing x\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input136.c",
    "content": "-35\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input137.c",
    "content": "x is 36\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input138.c",
    "content": "0 0 | 0\n0 1 | 0\n1 0 | 0\n1 1 | 1\n0 0 | 0\n0 1 | 1\n1 0 | 1\n1 1 | 1\naptr is NULL or doesn't point at 1\naptr points at 1\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input139.c",
    "content": "same apparently\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input140.c",
    "content": "0\n1\n4\n9\n16\n5 H\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input143.c",
    "content": "One of the three is NULL\nOne of the three is NULL\nOne of the three is NULL\nAll  three  are non-NULL\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input144.c",
    "content": "Unable to open fred: Success\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input145.c",
    "content": "q\nw\ne\nr\ne\n3\n5\n7\n9\n7\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input146.c",
    "content": "q\nw\ne\nr\ne\nr\ne\nr\ne\n\n3\n5\n7\n9\n7\n9\n7\n9\n7\n"
  },
  {
    "path": "58_Ptr_Increments/tests/out.input147.c",
    "content": "6\n9\n6\n9\n"
  },
  {
    "path": "58_Ptr_Increments/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "58_Ptr_Increments/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "58_Ptr_Increments/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->ctype = ctype;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n  int i;\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    case A_TOBOOL:\n      fprintf(stdout, \"A_TOBOOL\\n\");\n      return;\n    case A_LOGOR:\n      fprintf(stdout, \"A_LOGOR\\n\");\n      return;\n    case A_LOGAND:\n      fprintf(stdout, \"A_LOGAND\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "58_Ptr_Increments/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n\t\t\t    struct symtable *rctype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // For A_LOGOR and A_LOGAND, both types have to be int or pointer types\n  if (op==A_LOGOR || op==A_LOGAND) {\n    if (!inttype(ltype) && !ptrtype(ltype))\n      return(NULL);\n    if (!inttype(ltype) && !ptrtype(rtype))\n      return(NULL);\n    return (tree);\n  }\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, NULL, tree, NULL, 0));\n  }\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return (tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n  // We can scale only on add and subtract operations\n  if (op == A_ADD || op == A_SUBTRACT ||\n      op == A_ASPLUS || op == A_ASMINUS) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, rctype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h incdir.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\techo \"#define INCDIR \\\"$(INCDIR)\\\"\" > incdir.h\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\techo \"#define __NASM__ 1\" >> incdir.h\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\techo \"#define INCDIR \\\"$(INCDIR)\\\"\" > incdir.h\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\nincdir.h:\n\techo \"#define INCDIR \\\"$(INCDIR)\\\"\" > incdir.h\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwj0 cwj1 cwjarm compn compn0 compn1 *.o *.s out a.out incdir.h\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\n# Try to do the triple test\ntriple: cwj1\n\tsize cwj[01]\n\ncwj1: cwj0 $(SRCS) $(HSRCS)\n\t./cwj0 -o cwj1 $(SRCS)\n\ncwj0: install $(SRCS) $(HSRCS)\n\t./cwj  -o cwj0 $(SRCS)\n\n# Try to do the triple test with nasm\ntriplen: compn1\n\tsize compn[01]\n\ncompn1: compn0 $(SRCN) $(HSRCS)\n\t./compn0 -o compn1 $(SRCN)\n\ncompn0: installn $(SRCN) $(HSRCS)\n\t./compn  -o compn0 $(SRCN)\n"
  },
  {
    "path": "59_WDIW_pt1/Readme.md",
    "content": "# Part 59: Why Doesn't It Work, part 1\n\nWe've reached the **WDIW** stage: why doesn't it work? In this first part of this stage,\nI find a few easy to find bugs and fix them. That means there are some\nmore subtle bugs yet to be uncovered.\n\n## Bad Code Generation for `*argv[i]`\n\nI'm using `cwj` (the Gnu C compiled version) to build `cwj0`. The assembly\ncode in `cwj0` is *our* assembly code, not the assembly code generated by\nGnu C. So, when we run `cwj0`, any errors are because our assembly code isn't\ncorrect.\n\nThe first bug I noticed was that `*argv[i]` seemed to be generating code\nas if it was `(*argv)[i]`, i.e. always the *i'th* character of `*argv`, not\nthe first character at `argv[i]`.\n\nI first thought this was a parsing error, but no. It turned out that\nwe were not setting `argv[i]` as an rvalue before we dereferenced it.\nI worked this out by dumping the AST trees with both `cwj` and `cwj0` and\nobserving the differences between them. What we need to do is mark the expression *after*\nthe `*` token as an rvalue. This is now done in `prefix()` in `expr.c`:\n\n```c\nstatic struct ASTnode *prefix(int ptp) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  ...\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression.\n    // Make it an rvalue\n    scan(&Token);\n    tree = prefix(ptp);\n    tree->rvalue= 1;\n```\n\n## Externs are Also Globals\n\nThis one is going to keep biting me, I'm sure. I found another place where\nI wasn't treating an extern symbol as a global symbol. This was in `genAST()`\nin `gen.c` where we generate assignment assembly code. The fix is:\n\n```c\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n        case A_IDENT:\n          if (n->right->sym->class == C_GLOBAL ||\n              n->right->sym->class == C_EXTERN ||\n              n->right->sym->class == C_STATIC)\n            return (cgstorglob(leftreg, n->right->sym));\n          else\n            return (cgstorlocal(leftreg, n->right->sym));\n```\n\n## Scanning is Working\n\nAt this point, the `cwj0` compiler is reading source code input but not\ngenerating any output. Here are the new `Makefile` rules to do this:\n\n```\n# Try to do the triple test\ntriple: cwj1\n\ncwj1: cwj0 $(SRCS) $(HSRCS)\n        ./cwj0 -o cwj1 $(SRCS)\n\ncwj0: install $(SRCS) $(HSRCS)\n        ./cwj -o cwj0 $(SRCS)\n```\n\nSo, a `$ make triple` will build `cwj` with Gnu C, then build `cwj0` with\n`cwj`, and finally build `cwj1` with `cwj0`. I'll talk about this below.\n\nRight now, `cwj1` can't be created as there is no assembly output!\nThe question is, where is the compiler getting to? To find out, I\nadded a `printf()` to the bottom of `scan()`:\n\n```c\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  printf(\"Scanned %d\\n\", t->token);\n  return (1);\n```\n\nWith this added, I saw that\nboth `cwj` and `cwj0` scan 50,404 tokens and the resulting token streams are identical.\nThus, we can conclude that, up to `scan()`, things are working OK.\n\nHowever, the output of `./cwj0 -S -T cg.c` show no AST trees. If I\nrun `gdb cwj0`, set a breakpoint in `dumpAST()` and run it with the\n`-S -T cg.c` arguments, then we exit before we break at `dumpAST()`.\nWe also don't get to `function_declaration()`. So, why doesn't it work?\n\nAh, I spotted a memory access to `0(%rbp)`. This should never\nhappen as all locals are at negative locations relative to the frame pointer.\nIn `cgaddress()` in `cg.c`, we have another missed external test. We now have:\n\n```c\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL ||\n      sym->class == C_EXTERN ||\n      sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n```\n\nDamn these extern problems! Well, it's all my fault, so I need to take the blame\nhere.\n\n## Bad Comparisons\n\nWith the above change added, we are now failing with:\n\n```\n$ ./cwj0 -S tests/input001.c \ninvalid digit in integer literal:e on line 1 of tests/input001.c\n```\n\nThis turned out to be caused by this loop in `scanint()` in `scan.c()`:\n\n```c\nstatic int scanint(int c) {\n  int k;\n  ...\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n```\n\nWhat is happening is that the `k=` assignment is not only storing a result in memory, but it is being used as an expression. In this case the `k` result is being compared, i.e. `k >= 0`. Now, `k` is of type `int`, and we are performing this store to memory for its assignment:\n\n```\n    movl    %r10d, -8(%rbp)\n```\n\nWhen `chrpos()` returns `-1`, this gets truncated down to\n32 bits (`0xffffffff`) and stored in `-8(%rbp)`, i.e. in `k`. But in the\nfollowing comparison:\n\n```\n    movslq  -8(%rbp), %r10    # Load value back from k\n    movq    $0, %r11          # Load zero\n    cmpq    %r11, %r10        # Compare k's value against zero\n```\n\nwe load the *32-bit* value of `k` into `%r10`, and now do\na *64-bit* comparison. Well, as a 64-bit value, `0xffffffff`\nis a positive number, the loop comparison remains\ntrue and we don't leave the loop when we should.\n\nWhat we should do is use a different `cmp` instruction\nbased on the size of the operands in the comparison.\nI've made this change to `cgcompare_and_set()` in `cg.c`:\n\n```c\nint cgcompare_and_set(int ASTop, int r1, int r2, int type) {\n  int size = cgprimsize(type);\n  ...\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tcmpb\\t%s, %s\\n\", breglist[r2], breglist[r1]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tcmpl\\t%s, %s\\n\", dreglist[r2], dreglist[r1]);\n    break;\n  default:\n    fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  }\n  ...\n}\n```\n\nNow the correct comparison instruction is being used. There is a\nsimilar function, `cgcompare_and_jump()`, and at some stage I\nshould refactor and merge the two functions.\n\n# Now, So Close!\n\nWe are so close to passing what is informally known as\nthe **triple test**. In the triple test, we use an\nexisting compiler to build our compiler from source code\n(stage 1). Then we use this compiler to build itself\n(stage 2). Now, to prove that the compiler is self-compiling,\nwe use the stage 2 compiler to build itself, resulting\nin the stage 3 compiler.\n\nWe can now:\n\n + build `cwj` using the Gnu C compiler (stage 1)\n + build `cwj0` using the `cwj` compiler (stage 2)\n + build `cwj1` using the `cwj0` compiler (stage 3)\n\nHowever, the binary sizes for `cwj0` and `cwj1` don't match:\n\n```\n$ size cwj[01]\n   text    data     bss     dec     hex filename\n 109636    3028      48  112712   1b848 cwj0\n 109476    3028      48  112552   1b7a8 cwj1\n```\n\nand they should match *exactly*. Only when the\ncompiler can compile itself multiple times in\na row and produce the same result do we know\nthat it is self-compiling properly.\n\nUntil the results match exactly, there is\nsome subtle behaviour difference between\nstages 2 and 3, and so the compiler isn't\ncompiling itself consistently.\n\n## Conclusion and What's Next\n\nI didn't think I'd get to the point where I can build `cwj`, `cwj0` and\n`cwj1` in a single step of this journey. I expected we would have a whole\npile of bugs to fix before we got to this point.\n\nThe next problem is to work out why the stage 2 and stage 3 compilers are\ndifferent sizes. Looking at the `size` output, the data and bss sections\nare the same, but the amount of assembly code is different between the two\ncompilers.\n\nIn the next part of our compiler writing journey, we will try to do a\nside-by-side comparison of the assembly output between the different\nstages, and try to work out what is causing the difference.\n\n> P.S. In this part of the journey, I also started to add some assembly\n  output which would allow `gdb` to see the source line number that we\n  are stopped on. It isn't working yet, but in case you look, you will\n  see a new function `cglinenum()` in `cg.c`. When I get it working, I'll\nwrite up some commentary on it. [Next step](../60_TripleTest/Readme.md)\n"
  },
  {
    "path": "59_WDIW_pt1/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n  case P_CHAR:\n    return (1);\n  case P_INT:\n    return (4);\n  case P_LONG:\n    return (8);\n  default:\n    fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n  case P_CHAR:\n    return (offset);\n  case P_INT:\n  case P_LONG:\n    break;\n  default:\n    if (!ptrtype(type))\n      fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpopq\\t%s\\n\", reglist[r]);\n}\n\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  // fprintf(Outfile, \"# freeing all registers\\n\");\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg = 0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      // fprintf(Outfile, \"# allocated register %s\\n\", reglist[reg]);\n      return (reg);\n    }\n  }\n\n  // We have no registers, so we must spill one\n  reg = (spillreg % NUMFREEREGS);\n  spillreg++;\n  // fprintf(Outfile, \"# spilling reg %s\\n\", reglist[reg]);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0) {\n    // fprintf(Outfile, \"# error trying to free register %s\\n\", reglist[reg]);\n    fatald(\"Error trying to free register\", reg);\n  }\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg = (spillreg % NUMFREEREGS);\n    // fprintf(Outfile, \"# unspilling reg %s\\n\", reglist[reg]);\n    popreg(reg);\n  } else {\n    // fprintf(Outfile, \"# freeing reg %s\\n\", reglist[reg]);\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid spill_all_regs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void unspill_all_regs(void) {\n  int i;\n\n  for (i = NUMFREEREGS - 1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble(char *filename) {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile, \"\\t.file 1 \");\n  fputc('\"', Outfile);\n  fprintf(Outfile, \"%s\", filename);\n  fputc('\"', Outfile);\n  fputc('\\n', Outfile);\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"__switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"__next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     __no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"__no:\\n\"\n\t  \"        loop    __next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\" \"\\t.type\\t%s, @function\\n\", name, name);\n  fprintf(Outfile, \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\" \"\\tmovq\\t%%rsp, %%rbp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->size);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n  freeall_registers(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadvar(struct symtable *sym, int op) {\n  int r, postreg, offset = 1;\n\n  // Get a new register\n  r = alloc_register();\n\n  // If the symbol is a pointer, use the size\n  // of the type that it points to as any\n  // increment or decrement. If not, it's one.\n  if (ptrtype(sym->type))\n    offset = typesize(value_at(sym->type), sym->ctype);\n\n  // Negate the offset for decrements\n  if (op == A_PREDEC || op == A_POSTDEC)\n    offset = -offset;\n\n  // If we have a pre-operation\n  if (op == A_PREINC || op == A_PREDEC) {\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    else\n      fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\n    // and change the value at that address\n    switch (sym->size) {\n    case 1:\n      fprintf(Outfile, \"\\taddb\\t$%d,(%s)\\n\", offset, reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\taddl\\t$%d,(%s)\\n\", offset, reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\taddq\\t$%d,(%s)\\n\", offset, reglist[r]);\n      break;\n    }\n  }\n  // Now load the output register with the value\n  if (sym->class == C_LOCAL || sym->class == C_PARAM) {\n    switch (sym->size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    }\n  } else {\n    switch (sym->size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    }\n  }\n\n  // If we have a post-operation, get a new register\n  if (op == A_POSTINC || op == A_POSTDEC) {\n    postreg = alloc_register();\n\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn,\n\t      reglist[postreg]);\n    else\n      fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name,\n\t      reglist[postreg]);\n    // and change the value at that address\n\n    switch (sym->size) {\n    case 1:\n      fprintf(Outfile, \"\\taddb\\t$%d,(%s)\\n\", offset, reglist[postreg]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\taddl\\t$%d,(%s)\\n\", offset, reglist[postreg]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\taddq\\t$%d,(%s)\\n\", offset, reglist[postreg]);\n      break;\n    }\n    // and free the register\n    free_register(postreg);\n  }\n  // Return the register with the value\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Divide or modulo the first register by the second and\n// return the number of the register with the result\nint cgdivmod(int r1, int r2, int op) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  if (op == A_DIVIDE)\n    fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  else\n    fprintf(Outfile, \"\\tmovq\\t%%rdx,%s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", val, reglist[r]);\n}\n\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch (op) {\n  case A_IF:\n  case A_WHILE:\n  case A_LOGAND:\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n    break;\n  case A_LOGOR:\n    fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n    break;\n  default:\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n\n  // Unspill all the registers\n  unspill_all_regs();\n\n  // Get a new register and copy the return value into it\n  outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n  free_register(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->st_posn);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n      break;\n    case 8:\n      // Generate the pointer to a string literal. Treat a zero value\n      // as actually zero, not the label L0\n      if (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t  && initvalue != 0)\n\tfprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n      else\n\tfprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n      break;\n    default:\n      for (i = 0; i < size; i++)\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2, int type) {\n  int size = cgprimsize(type);\n\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tcmpb\\t%s, %s\\n\", breglist[r2], breglist[r1]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tcmpl\\t%s, %s\\n\", dreglist[r2], dreglist[r1]);\n    break;\n  default:\n    fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  }\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label, int type) {\n  int size = cgprimsize(type);\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tcmpb\\t%s, %s\\n\", breglist[r2], breglist[r1]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tcmpl\\t%s, %s\\n\", dreglist[r2], dreglist[r1]);\n    break;\n  default:\n    fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  }\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n\tbreak;\n      case P_LONG:\n\tfprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n\tbreak;\n      default:\n\tfatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL ||\n      sym->class == C_EXTERN || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  default:\n    fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tmovl\\t%s, (%s)\\n\", dreglist[r1], reglist[r2]);\n    break;\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\t__switch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n}\n\nvoid cglinenum(int line) {\n  fprintf(Outfile, \"\\t.loc 1 %d 0\\n\", line);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n   \"rdi\"\n};\nstatic char *breglist[] =\n { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n   \"dil\"\n};\nstatic char *dreglist[] =\n { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n  \"esi\", \"edi\"\n};\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpop\\t%s\\n\", reglist[r]);\n}\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\n\nvoid freeall_registers(int keepreg) {\n  int i;\n  // fprintf(Outfile, \"; freeing all registers\\n\");\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg = 0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      // fprintf(Outfile, \"; allocated register %s\\n\", reglist[reg]);\n      return (reg);\n    }\n  }\n  // We have no registers, so we must spill one\n  reg = (spillreg % NUMFREEREGS);\n  spillreg++;\n  // fprintf(Outfile, \"; spilling reg %s\\n\", reglist[reg]);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0) {\n    //fprintf(Outfile, \"# error trying to free register %s\\n\", reglist[reg]);\n    fatald(\"Error trying to free register\", reg);\n  }\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg = (spillreg % NUMFREEREGS);\n    // fprintf(Outfile, \"; unspilling reg %s\\n\", reglist[reg]);\n    popreg(reg);\n  } else {\n    // fprintf(Outfile, \"; freeing reg %s\\n\", reglist[reg]);\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid spill_all_regs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void unspill_all_regs(void) {\n  int i;\n\n  for (i = NUMFREEREGS - 1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble(char *filename) {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile, \";\\t%s\\n\", filename);\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"__switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"__next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    __no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"__no:\\n\"\n\t  \"        loop   __next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n//  if (sym->class == C_GLOBAL)\n  if(!sym->extinit) {\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", name);\n    sym->extinit = 1;\n  }\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->size);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n  freeall_registers(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadvar(struct symtable *sym, int op) {\n  int r, postreg, offset = 1;\n\n  if(!sym->extinit) {\n    fprintf(Outfile, \"extern\\t%s\\n\", sym->name);\n    sym->extinit = 1;\n  }\n\n  // Get a new register\n  r = alloc_register();\n\n  // If the symbol is a pointer, use the size\n  // of the type that it points to as any\n  // increment or decrement. If not, it's one.\n  if (ptrtype(sym->type))\n    offset = typesize(value_at(sym->type), sym->ctype);\n\n  // Negate the offset for decrements\n  if (op == A_PREDEC || op == A_POSTDEC)\n    offset = -offset;\n\n  // If we have a pre-operation\n  if (op == A_PREINC || op == A_PREDEC) {\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r], sym->st_posn);\n    else\n      fprintf(Outfile, \"\\tlea\\t%s, [%s]\\n\", reglist[r], sym->name);\n\n    // and change the value at that address\n    switch (sym->size) {\n      case 1:\n        fprintf(Outfile, \"\\tadd\\tbyte [%s], %d\\n\", reglist[r], offset);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tadd\\tdword [%s], %d\\n\", reglist[r], offset);\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tadd\\tqword [%s], %d\\n\", reglist[r], offset);\n        break;\n    }\n  }\n\n  // Now load the output register with the value\n  if (sym->class == C_LOCAL || sym->class == C_PARAM) {\n    switch (sym->size) {\n      case 1:\n        fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], sym->st_posn);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tmovsxd\\t%s, dword [rbp+%d]\\n\", reglist[r], sym->st_posn);\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r], sym->st_posn);\n    }\n  } else {\n    switch (sym->size) {\n      case 1:\n        fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], sym->name);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tmovsxd\\t%s, dword [%s]\\n\", reglist[r], sym->name);\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    }\n  }\n\n  // If we have a post-operation, get a new register\n  if (op == A_POSTINC || op == A_POSTDEC) {\n    postreg = alloc_register();\n\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[postreg], sym->st_posn);\n    else\n      fprintf(Outfile, \"\\tlea\\t%s, [%s]\\n\", reglist[postreg], sym->name);\n    // and change the value at that address\n\n    switch (sym->size) {\n      case 1:\n        fprintf(Outfile, \"\\tadd\\tbyte [%s], %d\\n\", reglist[postreg], offset);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tadd\\tdword [%s], %d\\n\", reglist[postreg], offset);\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tadd\\tqword [%s], %d\\n\", reglist[postreg], offset);\n        break;\n    }\n    // and free the register\n    free_register(postreg);\n  }\n\n  // Return the register with the value\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Divide or modulo the first register by the second and\n// return the number of the register with the result\nint cgdivmod(int r1, int r2, int op) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  if (op == A_DIVIDE)\n    fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  else\n    fprintf(Outfile, \"\\tmov\\t%s, rdx\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], val);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch (op) {\n    case A_IF:\n    case A_WHILE:\n    case A_LOGAND:\n      fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n      break;\n    case A_LOGOR:\n      fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n      break;\n    default:\n      fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  if(!sym->extinit) {\n    fprintf(Outfile, \"extern\\t%s\\n\", sym->name);\n    sym->extinit = 1;\n  }\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // Unspill all the registers\n  unspill_all_regs();\n  // Get a new register and copy the return value into it\n  outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n  free_register(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if(!sym->extinit) {\n    fprintf(Outfile, \"extern\\t%s\\n\", sym->name);\n    sym->extinit = 1;\n  }\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", node->name);\n  if(!node->extinit) {\n    node->extinit = 1;\n  }\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n    }\n  }\n\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2, int type) {\n  int size = cgprimsize(type);\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", breglist[r1], breglist[r2]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", dreglist[r1], dreglist[r2]);\n      break;\n    default:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  }\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label, int type) {\n  int size = cgprimsize(type);\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", breglist[r1], breglist[r2]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", dreglist[r1], dreglist[r2]);\n      break;\n    default:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  }\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n        case P_CHAR:\n          fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n          break;\n        case P_INT:\n          fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n          break;\n        case P_LONG:\n          fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n          break;\n        default:\n          fatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (!sym->extinit) {\n    fprintf(Outfile, \"extern\\t%s\\n\", sym->name);\n    sym->extinit = 1;\n  }\n\n  if (sym->class == C_GLOBAL ||\n      sym->class == C_EXTERN || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmov\\t[%s], dword %s\\n\", reglist[r2], dreglist[r1]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\t__switch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n}\n\nvoid cglinenum(int line) {\n  //fprintf(Outfile, \";\\t.loc 1 %d 0\\n\", line);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Linestart;\t\t     \t// True if at start of a line\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\nextern char *Tstring[];\t\t\t// List of token strings\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_dumpsym;\t\t// If true, dump the symbol table\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "59_WDIW_pt1/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Get the type inside the parentheses\n  type = parse_stars(parse_type(ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return (type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree = optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type = tree->type;\n    tree = tree->left;\n  }\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return (tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue == 0)\n      return (0);\n  }\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return (tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a pointer to a symbol that may already exist\n// return true if this symbol doesn't exist. We use\n// this function to convert externs into globals\nint is_new_symbol(struct symtable *sym, int class, \n\t\t  int type, struct symtable *ctype) {\n\n  // There is no existing symbol, thus is new\n  if (sym==NULL) return(1);\n\n  // global versus extern: if they match that it's not new\n  // and we can convert the class to global\n  if ((sym->class== C_GLOBAL && class== C_EXTERN)\n      || (sym->class== C_EXTERN && class== C_GLOBAL)) {\n\n      // If the types don't match, there's a problem\n      if (type != sym->type)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // Struct/unions, also compare the ctype\n      if (type >= P_STRUCT && ctype != sym->ctype)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // If we get to here, the types match, so mark the symbol\n      // as global\n      sym->class= C_GLOBAL;\n      // Return that symbol is not new\n      return(0);\n  }\n\n  // It must be a duplicate symbol if we get here\n  fatals(\"Duplicate global variable declaration\", sym->name);\n  return(-1);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree = NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, type, ctype))\n        sym = addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym = addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym = addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist = (int *) malloc(sizeof(int));\n      sym->initlist[0] = parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym->ctype, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, varnode->ctype, 0);\n      if (exprnode == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode->ctype, exprnode,\n\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t\t// New symbol table entry\n  int nelems = -1;\t\t// Assume the number of elements won't be given\n  int maxelems;\t\t\t// The maximum number of elements in the init list\n  int *initlist;\t\t// The list of initial elements \n  int i = 0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems = parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, pointer_to(type), ctype))\n        sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class, 0, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, pointer_to(type), ctype, S_ARRAY, 0);\n      break;\n    default:\n      fatal(\"Declaration of array parameters is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems = nelems;\n    else\n      maxelems = TABLE_INCREMENT;\n    initlist = (int *) malloc(maxelems * sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n\tfatal(\"Too many values in initialisation list\");\n\n      initlist[i++] = parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n\tmaxelems += TABLE_INCREMENT;\n\tinitlist = (int *) realloc(initlist, maxelems * sizeof(int));\n      }\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n\tscan(&Token);\n\tbreak;\n      }\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j = i; j < sym->nelems; j++)\n      initlist[j] = 0;\n    if (i > nelems)\n      nelems = i;\n    sym->initlist = initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  // Only externs can have no elements.\n  if (class != C_EXTERN && nelems<=0)\n    fatals(\"Array must have non-zero elements\", sym->name);\n\n  sym->nelems = nelems;\n  sym->size = sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n\tparamcnt = 0;\n\tscan(&Token);\n\tbreak;\n      }\n    }\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n  int linenum= Line;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, ctype, tree, oldfuncsym, endlabel);\n  tree->linenum= linenum;\n\n  // Do optimisations on the AST tree\n  tree = optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t = declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t == -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead == NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name = NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET) {\n    sym = array_declaration(varname, type, ctype, class);\n    *tree= NULL;\t// Local arrays are not initialised\n  } else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree = NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n\tfatal(\"Function definition not at global level\");\n      return (type);\n    }\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree == NULL)\n      *gluetree = tree;\n    else\n      *gluetree =\n\tmkastnode(A_GLUE, P_NONE, NULL, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n  return(0);\t// Keep -Wall happy\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype= NULL;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "59_WDIW_pt1/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int level);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble(char *filename);\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue, int append);\nvoid genglobstrend(void);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nint alloc_register(void);\nvoid freeall_registers(int keepreg);\nvoid spill_all_regs(void);\nvoid cgpreamble(char *filename);\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadvar(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdivmod(int r1, int r2, int op);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue, int append);\nvoid cgglobstrend(void);\nint cgcompare_and_set(int ASTop, int r1, int r2, int type);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label, int type);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nvoid cgloadboolean(int r, int val);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2);\nvoid cglinenum(int line);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\nvoid dumptable(struct symtable *head, char *name, int indent);\nvoid dumpsymtables(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(struct symtable **ctype);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n                            struct symtable *rctype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "59_WDIW_pt1/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n#include \"incdir.h\"\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -g -f elf64 -w-ptr -o \"\n#define LDCMD \"cc -g -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -g -o \"\n#define LDCMD \"cc -g -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH, T_ASMOD,\n  T_QUESTION, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH, T_MOD,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR,\t\t\t//  1\n  A_ASSLASH, A_ASMOD, A_TERNARY, A_LOGOR,\t\t\t//  5\n  A_LOGAND, A_OR, A_XOR, A_AND, A_EQ, A_NE, A_LT,\t\t//  9\n  A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\t\t\t\t// 16\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_MOD,\t\t// 21\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\t\t\t\t// 26\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\t\t\t// 30\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\t\t\t\t// 35\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\t\t\t// 39\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\t\t// 43\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\t\t// 48\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n#ifdef __NASM__\n  int extinit;\n#endif\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n  int linenum;\t\t\t// Line number from where this node comes\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "59_WDIW_pt1/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree =\n      mkastnode(A_GLUE, P_NONE, NULL, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree =\n    mkastunary(A_FUNCCALL, funcptr->type, funcptr->ctype, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(struct ASTnode *left) {\n  struct ASTnode *right;\n\n  // Check that the sub-tree is a pointer\n  if (!ptrtype(left->type))\n    fatal(\"Not an array or pointer\");\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, left->ctype, A_ADD);\n\n  // Return an AST tree where the array's base has the offset added to it,\n  // and dereference the element. Still an lvalue at this point.\n  left =\n    mkastnode(A_ADD, left->type, left->ctype, left, NULL, right, NULL, 0);\n  left =\n    mkastunary(A_DEREF, value_at(left->type), left->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(struct ASTnode *left, int withpointer) {\n  struct ASTnode *right;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the left AST tree is a pointer to struct or union\n  if (withpointer && left->type != pointer_to(P_STRUCT)\n      && left->type != pointer_to(P_UNION))\n    fatal(\"Expression is not a pointer to a struct/union\");\n\n  // Or, check that the left AST tree is a struct or union.\n  // If so, change it from an A_IDENT to an A_ADDR so that\n  // we get the base address, not the value at this address.\n  if (!withpointer) {\n    if (left->type == P_STRUCT || left->type == P_UNION)\n      left->op = A_ADDR;\n    else\n      fatal(\"Expression is not a struct/union\");\n  }\n\n  // Get the details of the composite type\n  typeptr = left->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left =\n    mkastnode(A_ADD, pointer_to(m->type), m->ctype, left, NULL, right, NULL,\n\t      0);\n  left = mkastunary(A_DEREF, m->type, m->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse a parenthesised expression and\n// return an AST node representing it.\nstatic struct ASTnode *paren_expression(int ptp) {\n  struct ASTnode *n;\n  int type = 0;\n  struct symtable *ctype = NULL;\n\n  // Beginning of a parenthesised expression, skip the '('.\n  scan(&Token);\n\n  // If the token after is a type identifier, this is a cast expression\n  switch (Token.token) {\n  case T_IDENT:\n    // We have to see if the identifier matches a typedef.\n    // If not, treat it as an expression.\n    if (findtypedef(Text) == NULL) {\n      n = binexpr(0);\t// ptp is zero as expression inside ( )\n      break;\n    }\n  case T_VOID:\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n  case T_STRUCT:\n  case T_UNION:\n  case T_ENUM:\n    // Get the type inside the parentheses\n    type = parse_cast(&ctype);\n\n    // Skip the closing ')' and then parse the following expression\n    rparen();\n\n  default:\n    n = binexpr(ptp);\t\t// Scan in the expression. We pass in ptp\n\t\t\t\t// as the cast doesn't change the\n\t\t\t\t// expression's precedence\n  }\n\n  // We now have at least an expression in n, and possibly a non-zero type\n  // in type if there was a cast. Skip the closing ')' if there was no cast.\n  if (type == 0)\n    rparen();\n  else\n    // Otherwise, make a unary AST node for the cast\n    n = mkastunary(A_CAST, type, ctype, n, NULL, 0);\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(int ptp) {\n  struct ASTnode *n;\n  struct symtable *enumptr;\n  struct symtable *varptr;\n  int id;\n  int type = 0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type = parse_stars(parse_type(&ctype, &class));\n\n    // Get the type's size\n    size = typesize(type, ctype);\n    rparen();\n\n    // Make a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    id = genglobstr(Text, 0);\n\n    // For successive STRLIT tokens, append their contents\n    // to this one\n    while (1) {\n      scan(&Peektoken);\n      if (Peektoken.token != T_STRLIT) break;\n      genglobstr(Text, 1);\n      scan(&Token);\t// To skip it properly\n    }\n\n    // Now make a leaf AST node for it. id is the string's label.\n    genglobstrend();\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, NULL, id);\n    break;\n\n  case T_IDENT:\n    // If the identifier matches an enum value,\n    // return an A_INTLIT node\n    if ((enumptr = findenumval(Text)) != NULL) {\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, enumptr->st_posn);\n      break;\n    }\n    // See if this identifier exists as a symbol. For arrays, set rvalue to 1.\n    if ((varptr = findsymbol(Text)) == NULL)\n      fatals(\"Unknown variable or function\", Text);\n    switch (varptr->stype) {\n    case S_VARIABLE:\n      n = mkastleaf(A_IDENT, varptr->type, varptr->ctype, varptr, 0);\n      break;\n    case S_ARRAY:\n      n = mkastleaf(A_ADDR, varptr->type, varptr->ctype, varptr, 0);\n      n->rvalue = 1;\n      break;\n    case S_FUNCTION:\n      // Function call, see if the next token is a left parenthesis\n      scan(&Token);\n      if (Token.token != T_LPAREN)\n\tfatals(\"Function name used without parentheses\", Text);\n      return (funccall());\n    default:\n      fatals(\"Identifier not a scalar or array variable\", Text);\n    }\n    break;\n\n  case T_LPAREN:\n    return (paren_expression(ptp));\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(int ptp) {\n  struct ASTnode *n;\n\n  // Get the primary expression\n  n = primary(ptp);\n\n  // Loop until there are no more postfix operators\n  while (1) {\n    switch (Token.token) {\n    case T_LBRACKET:\n      // An array reference\n      n = array_access(n);\n      break;\n\n    case T_DOT:\n      // Access into a struct or union\n      n = member_access(n, 0);\n      break;\n\n    case T_ARROW:\n      // Pointer access into a struct or union\n      n = member_access(n, 1);\n      break;\n\n    case T_INC:\n      // Post-increment: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot ++ on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTINC;\n      break;\n\n    case T_DEC:\n      // Post-decrement: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot -- on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTDEC;\n      break;\n\n    default:\n      return (n);\n    }\n  }\n\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_MOD)\n    return (tokentype);\n  fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10,\t\t\t// T_ASMINUS, T_ASSTAR,\n  10, 10,\t\t\t// T_ASSLASH, T_ASMOD,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110, 110\t\t\t// T_STAR, T_SLASH, T_MOD\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_MOD)\n    fatals(\"Token with no precedence in op_precedence:\", Tstring[tokentype]);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (prec);\n}\n\n// prefix_expression: postfix_expression\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstatic struct ASTnode *prefix(int ptp) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Prevent '&' being performed on an array\n    if (tree->sym->stype == S_ARRAY)\n      fatal(\"& operator cannot be performed on an array\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression.\n    // Make it an rvalue\n    scan(&Token);\n    tree = prefix(ptp);\n    tree->rvalue= 1;\n\n    // Ensure the tree's type is a pointer\n    if (!ptrtype(tree->type))\n      fatal(\"* operator must be followed by an expression of pointer type\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree =\n      mkastunary(A_DEREF, value_at(tree->type), tree->ctype, tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this if needed to int so that it's signed\n    tree->rvalue = 1;\n    if (tree->type == P_CHAR)\n      tree->type = P_INT;\n    tree = mkastunary(A_NEGATE, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  default:\n    tree = postfix(ptp);\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix(ptp);\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp = binexpr(0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. XXX We should also\n      // consider the third expression's type.\n      return (mkastnode\n\t      (A_TERNARY, right->type, right->ctype, left, right, ltemp,\n\t       NULL, 0));\n\n    case A_ASSIGN:\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, left->ctype, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n      break;\n\n    default:\n      // We are not doing a ternary or assignment, so both trees should\n      // be rvalues. Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, right->ctype, ASTop);\n      rtemp = modify_type(right, left->type, left->ctype, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left->ctype, left, NULL,\n\t\tright, NULL, 0);\n\n    // Some operators produce an int result regardless of their operands\n    switch (binastop(tokentype)) {\n    case A_LOGOR:\n    case A_LOGAND:\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      left->type = P_INT;\n    }\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\nstatic void update_line(struct ASTnode *n) {\n  // Output the line into the assembly if we've\n  // changed the line number in the AST node\n  if (n->linenum != 0 && Line != n->linenum) {\n    Line = n->linenum;\n    cglinenum(Line);\n  }\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs(reg);\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    if (c->left)\n      genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs(NOREG);\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for an\n// A_LOGAND or A_LOGOR operation\nstatic int gen_logandor(struct ASTnode *n) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n  int reg;\n\n  // Generate the code for the left expression\n  // followed by the jump to the false label\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(NOREG);\n\n  // Generate the code for the right expression\n  // followed by the jump to the false label\n  reg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(reg);\n\n  // We didn't jump so set the right boolean value\n  if (n->op == A_LOGAND) {\n    cgloadboolean(reg, 1);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 0);\n  } else {\n    cgloadboolean(reg, 0);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 1);\n  }\n  cglabel(Lend);\n  return (reg);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // Save the registers before we copy the arguments\n  spill_all_regs();\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  // Don't free the register holding the result, though!\n  genfreeregs(reg);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg = NOREG, rightreg = NOREG;\n\n  // Empty tree, do nothing\n  if (n == NULL)\n    return (NOREG);\n\n  // Update the line number in the output\n  update_line(n);\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n  case A_IF:\n    return (genIF(n, looptoplabel, loopendlabel));\n  case A_WHILE:\n    return (genWHILE(n));\n  case A_SWITCH:\n    return (genSWITCH(n));\n  case A_FUNCCALL:\n    return (gen_funccall(n));\n  case A_TERNARY:\n    return (gen_ternary(n));\n  case A_LOGOR:\n    return (gen_logandor(n));\n  case A_LOGAND:\n    return (gen_logandor(n));\n  case A_GLUE:\n    // Do each child statement, and free the\n    // registers after each child\n    if (n->left != NULL)\n      genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    if (n->right != NULL)\n      genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    return (NOREG);\n  case A_FUNCTION:\n    // Generate the function's preamble before the code\n    // in the child sub-tree\n    cgfuncpreamble(n->sym);\n    genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n    cgfuncpostamble(n->sym);\n    return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n  case A_ADD:\n    return (cgadd(leftreg, rightreg));\n  case A_SUBTRACT:\n    return (cgsub(leftreg, rightreg));\n  case A_MULTIPLY:\n    return (cgmul(leftreg, rightreg));\n  case A_DIVIDE:\n    return (cgdivmod(leftreg, rightreg, A_DIVIDE));\n  case A_MOD:\n    return (cgdivmod(leftreg, rightreg, A_MOD));\n  case A_AND:\n    return (cgand(leftreg, rightreg));\n  case A_OR:\n    return (cgor(leftreg, rightreg));\n  case A_XOR:\n    return (cgxor(leftreg, rightreg));\n  case A_LSHIFT:\n    return (cgshl(leftreg, rightreg));\n  case A_RSHIFT:\n    return (cgshr(leftreg, rightreg));\n  case A_EQ:\n  case A_NE:\n  case A_LT:\n  case A_GT:\n  case A_LE:\n  case A_GE:\n    // If the parent AST node is an A_IF, A_WHILE or A_TERNARY,\n    // generate a compare followed by a jump. Otherwise, compare\n    // registers and set one to 1 or 0 based on the comparison.\n    if (parentASTop == A_IF || parentASTop == A_WHILE ||\n\tparentASTop == A_TERNARY)\n      return (cgcompare_and_jump\n\t      (n->op, leftreg, rightreg, iflabel, n->left->type));\n    else\n      return (cgcompare_and_set(n->op, leftreg, rightreg, n->left->type));\n  case A_INTLIT:\n    return (cgloadint(n->a_intvalue, n->type));\n  case A_STRLIT:\n    return (cgloadglobstr(n->a_intvalue));\n  case A_IDENT:\n    // Load our value if we are an rvalue\n    // or we are being dereferenced\n    if (n->rvalue || parentASTop == A_DEREF) {\n      return (cgloadvar(n->sym, n->op));\n    } else\n      return (NOREG);\n  case A_ASPLUS:\n  case A_ASMINUS:\n  case A_ASSTAR:\n  case A_ASSLASH:\n  case A_ASMOD:\n  case A_ASSIGN:\n\n    // For the '+=' and friends operators, generate suitable code\n    // and get the register with the result. Then take the left child,\n    // make it the right child so that we can fall into the assignment code.\n    switch (n->op) {\n    case A_ASPLUS:\n      leftreg = cgadd(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASMINUS:\n      leftreg = cgsub(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASSTAR:\n      leftreg = cgmul(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASSLASH:\n      leftreg = cgdivmod(leftreg, rightreg, A_DIVIDE);\n      n->right = n->left;\n      break;\n    case A_ASMOD:\n      leftreg = cgdivmod(leftreg, rightreg, A_MOD);\n      n->right = n->left;\n      break;\n    }\n\n    // Now into the assignment code\n    // Are we assigning to an identifier or through a pointer?\n    switch (n->right->op) {\n    case A_IDENT:\n      if (n->right->sym->class == C_GLOBAL ||\n\t  n->right->sym->class == C_EXTERN ||\n\t  n->right->sym->class == C_STATIC)\n\treturn (cgstorglob(leftreg, n->right->sym));\n      else\n\treturn (cgstorlocal(leftreg, n->right->sym));\n    case A_DEREF:\n      return (cgstorderef(leftreg, rightreg, n->right->type));\n    default:\n      fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n    }\n  case A_WIDEN:\n    // Widen the child's type to the parent's type\n    return (cgwiden(leftreg, n->left->type, n->type));\n  case A_RETURN:\n    cgreturn(leftreg, Functionid);\n    return (NOREG);\n  case A_ADDR:\n    return (cgaddress(n->sym));\n  case A_DEREF:\n    // If we are an rvalue, dereference to get the value we point at,\n    // otherwise leave it for A_ASSIGN to store through the pointer\n    if (n->rvalue)\n      return (cgderef(leftreg, n->left->type));\n    else\n      return (leftreg);\n  case A_SCALE:\n    // Small optimisation: use shift if the\n    // scale value is a known power of two\n    switch (n->a_size) {\n    case 2:\n      return (cgshlconst(leftreg, 1));\n    case 4:\n      return (cgshlconst(leftreg, 2));\n    case 8:\n      return (cgshlconst(leftreg, 3));\n    default:\n      // Load a register with the size and\n      // multiply the leftreg by this size\n      rightreg = cgloadint(n->a_size, P_INT);\n      return (cgmul(leftreg, rightreg));\n    }\n  case A_POSTINC:\n  case A_POSTDEC:\n    // Load and decrement the variable's value into a register\n    // and post increment/decrement it\n    return (cgloadvar(n->sym, n->op));\n  case A_PREINC:\n  case A_PREDEC:\n    // Load and decrement the variable's value into a register\n    // and pre increment/decrement it\n    return (cgloadvar(n->left->sym, n->op));\n  case A_NEGATE:\n    return (cgnegate(leftreg));\n  case A_INVERT:\n    return (cginvert(leftreg));\n  case A_LOGNOT:\n    return (cglognot(leftreg));\n  case A_TOBOOL:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, set the register\n    // to 0 or 1 based on it's zeroeness or non-zeroeness\n    return (cgboolean(leftreg, parentASTop, iflabel));\n  case A_BREAK:\n    cgjump(loopendlabel);\n    return (NOREG);\n  case A_CONTINUE:\n    cgjump(looptoplabel);\n    return (NOREG);\n  case A_CAST:\n    return (leftreg);\t\t// Not much to do\n  default:\n    fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble(char *filename) {\n  cgpreamble(filename);\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs(int keepreg) {\n  freeall_registers(keepreg);\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\n\n// Generate a global string.\n// If append is true, append to\n// previous genglobstr() call.\nint genglobstr(char *strvalue, int append) {\n  int l = genlabel();\n  cgglobstr(l, strvalue, append);\n  return (l);\n}\nvoid genglobstrend(void) {\n  cgglobstrend();\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "59_WDIW_pt1/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\nint toupper(int c);\nint tolower(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "59_WDIW_pt1/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n\nint * __errno_location(void);\n\n#define errno (* __errno_location())\n\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "59_WDIW_pt1/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "59_WDIW_pt1/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "59_WDIW_pt1/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n#ifndef EOF\n# define EOF (-1)\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint sprintf(char *str, char *format);\nint snprintf(char *str, size_t size, char *format);\nint fgetc(FILE *stream);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\nFILE *popen(char *command, char *type);\nint pclose(FILE *stream);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "59_WDIW_pt1/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\nint system(char *command);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "59_WDIW_pt1/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\nint strcmp(char *s1, char *s2);\nint strncmp(char *s1, char *s2, size_t n);\nchar *strerror(int errnum);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "59_WDIW_pt1/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "59_WDIW_pt1/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix;\n  posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Linestart = 1;\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token = 0;\t\t// and set there is no lookahead token\n  genpreamble(filename);\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n\n  // Dump the symbol table if requested\n  if (O_dumpsym) {\n    printf(\"Symbols for %s\\n\", filename);\n    dumpsymtables();\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n#ifdef __NASM__\n  char *incfilename = alter_suffix(filename, 'n');\n  if (incfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  sprintf(cmd, \"%s %s %s\", ASCMD, outfilename, filename);\n#else\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n#endif\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char **objlist) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcSTM] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -M dump the symbol table for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char **argv) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, j, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_dumpsym = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'M':\n\t  O_dumpsym = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  int i;\n  for (i = 0; s[i] != '\\0'; i++)\n    if (s[i] == (char) c)\n      return (i);\n  return (-1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (Linestart && c == '#') {\t// We've hit a pre-processor statement\n    Linestart = 0;\t\t// No longer at the start of the line\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n\n  Linestart = 0;\t\t// No longer at the start of the line\n  if ('\\n' == c) {\n    Line++;\t\t\t// Increment line count\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return (n);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn (hexchar());\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = (char)c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = (char)c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\", \"%=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"%\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case '%':\n      if ((c = next()) == '=') {\n\tt->token = T_ASMOD;\n      } else {\n\tputback(c);\n\tt->token = T_MOD;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, NULL, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, NULL, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, NULL, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree= NULL;\n\n  // Ensure we have 'return'\n  match(T_RETURN, \"return\");\n\n  // See if we have a return value\n  if (Token.token == T_LPAREN) {\n    // Can't return a value if function returns P_VOID\n    if (Functionid->type == P_VOID)\n      fatal(\"Can't return from a void function\");\n\n    // Skip the left parenthesis\n    lparen();\n\n    // Parse the following expression\n    tree = binexpr(0);\n\n    // Ensure this is compatible with the function's type\n    tree = modify_type(tree, Functionid->type, Functionid->ctype, 0);\n    if (tree == NULL)\n      fatal(\"Incompatible type to return\");\n\n    // Get the ')'\n    rparen();\n  }\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, NULL, tree, NULL, 0);\n\n  // Get the ';'\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, P_NONE, NULL, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, P_NONE, NULL, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *body, *n, *c;\n  struct ASTnode *casetree = NULL, *casetail;\n  int inloop = 1, casecount = 0;\n  int seendefault = 0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left = binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n = mkastunary(A_SWITCH, P_NONE, NULL, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch (Token.token) {\n\t// Leave the loop when we hit a '}'\n      case T_RBRACE:\n\tif (casecount == 0)\n\t  fatal(\"No cases in switch\");\n\tinloop = 0;\n\tbreak;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token == T_DEFAULT) {\n\t  ASTop = A_DEFAULT;\n\t  seendefault = 1;\n\t  scan(&Token);\n\t} else {\n\t  ASTop = A_CASE;\n\t  scan(&Token);\n\t  left = binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue = left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n\t  // that there isn't a duplicate case value\n\t  for (c = casetree; c != NULL; c = c->right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n\t}\n\n\t// Scan the ':' and increment the casecount\n\tmatch(T_COLON, \":\");\n\tcasecount++;\n\n\t// If the next token is a T_CASE, the existing case will fall\n\t// into the next case. Otherwise, parse the case body.\n\tif (Token.token == T_CASE)\n\t  body = NULL;\n\telse\n\t  body = compound_statement(1);\n\n\t// Build a sub-tree with any compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree == NULL) {\n\t  casetree = casetail =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t} else {\n\t  casetail->right =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t  casetail = casetail->right;\n\t}\n\tbreak;\n      default:\n\tfatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue = casecount;\n  n->right = casetree;\n  rbrace();\n\n  return (n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n  int linenum= Line;\n\n  switch (Token.token) {\n    case T_SEMI:\n      // An empty statement\n      semi();\n      break;\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      stmt->linenum= linenum;\n      rbrace();\n      return (stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt = binexpr(0);\n        stmt->linenum= linenum;\n\tsemi();\n\treturn (stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      stmt= if_statement(); stmt->linenum= linenum; return(stmt);\n    case T_WHILE:\n      stmt= while_statement(); stmt->linenum= linenum; return(stmt);\n    case T_FOR:\n      stmt= for_statement(); stmt->linenum= linenum; return(stmt);\n    case T_RETURN:\n      stmt= return_statement(); stmt->linenum= linenum; return(stmt);\n    case T_BREAK:\n      stmt= break_statement(); stmt->linenum= linenum; return(stmt);\n    case T_CONTINUE:\n      stmt= continue_statement(); stmt->linenum= linenum; return(stmt);\n    case T_SWITCH:\n      stmt= switch_statement(); stmt->linenum= linenum; return(stmt);\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt = binexpr(0);\n      stmt->linenum= linenum;\n      semi();\n      return (stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Leave if we've hit the end token. We do this first to allow\n    // an empty compound statement\n    if (Token.token == T_RBRACE)\n      return (left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT))\n      return (left);\n\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, NULL, left, NULL, tree, NULL, 0);\n    }\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n"
  },
  {
    "path": "59_WDIW_pt1/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n#ifdef __NASM__\n  node->extinit = 0;\n#endif\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list,\n\t\t\t\t      int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class == 0 || class == list->class)\n\treturn (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead = Globtail = NULL;\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Membhead = Membtail = NULL;\n  Structhead = Structtail = NULL;\n  Unionhead = Uniontail = NULL;\n  Enumhead = Enumtail = NULL;\n  Typehead = Typetail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev = NULL;\n\n  // Walk the global table looking for static entries\n  for (g = Globhead; g != NULL; g = g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL)\n\tprev->next = g->next;\n      else\n\tGlobhead->next = g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n\tif (prev != NULL)\n\t  Globtail = prev;\n\telse\n\t  Globtail = Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev = g;\n}\n\n// Dump a single symbol\nstatic void dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n    case P_VOID:\n      printf(\"void \");\n      break;\n    case P_CHAR:\n      printf(\"char \");\n      break;\n    case P_INT:\n      printf(\"int \");\n      break;\n    case P_LONG:\n      printf(\"long \");\n      break;\n    case P_STRUCT:\n      if (sym->ctype != NULL)\n\tprintf(\"struct %s \", sym->ctype->name);\n      else\n\tprintf(\"struct %s \", sym->name);\n      break;\n    case P_UNION:\n      if (sym->ctype != NULL)\n\tprintf(\"union %s \", sym->ctype->name);\n      else\n\tprintf(\"union %s \", sym->name);\n      break;\n    default:\n      printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++)\n    printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      break;\n    case S_FUNCTION:\n      printf(\"()\");\n      break;\n    case S_ARRAY:\n      printf(\"[]\");\n      break;\n    default:\n      printf(\" unknown stype\");\n  }\n\n  switch (sym->class) {\n    case C_GLOBAL:\n      printf(\": global\");\n      break;\n    case C_LOCAL:\n      printf(\": local\");\n      break;\n    case C_PARAM:\n      printf(\": param\");\n      break;\n    case C_EXTERN:\n      printf(\": extern\");\n      break;\n    case C_STATIC:\n      printf(\": static\");\n      break;\n    case C_STRUCT:\n      printf(\": struct\");\n      break;\n    case C_UNION:\n      printf(\": union\");\n      break;\n    case C_MEMBER:\n      printf(\": member\");\n      break;\n    case C_ENUMTYPE:\n      printf(\": enumtype\");\n      break;\n    case C_ENUMVAL:\n      printf(\": enumval\");\n      break;\n    case C_TYPEDEF:\n      printf(\": typedef\");\n      break;\n    default:\n      printf(\": unknown class\");\n  }\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      if (sym->class == C_ENUMVAL)\n\tprintf(\", value %d\\n\", sym->st_posn);\n      else\n\tprintf(\", size %d\\n\", sym->size);\n      break;\n    case S_FUNCTION:\n      printf(\", %d params\\n\", sym->nelems);\n      break;\n    case S_ARRAY:\n      printf(\", %d elems, size %d\\n\", sym->nelems, sym->size);\n      break;\n  }\n\n  switch (sym->type & (~0xf)) {\n    case P_STRUCT:\n    case P_UNION:\n      dumptable(sym->member, NULL, 4);\n  }\n\n  switch (sym->stype) {\n    case S_FUNCTION:\n      dumptable(sym->member, NULL, 4);\n  }\n}\n\n// Dump one symbol table\nvoid dumptable(struct symtable *head, char *name, int indent) {\n  struct symtable *sym;\n\n  if (head != NULL && name != NULL)\n    printf(\"%s\\n--------\\n\", name);\n  for (sym = head; sym != NULL; sym = sym->next)\n    dumpsym(sym, indent);\n}\n\nvoid dumpsymtables(void) {\n  dumptable(Globhead, \"Global\", 0);\n  printf(\"\\n\");\n  dumptable(Enumhead, \"Enums\", 0);\n  printf(\"\\n\");\n  dumptable(Typehead, \"Typedefs\", 0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input032.c",
    "content": "Unknown variable or function:pizza on line 4 of input032.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input042.c",
    "content": "Unknown variable or function:fred on line 3 of input042.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input043.c",
    "content": "Unknown variable or function:b on line 3 of input043.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input044.c",
    "content": "Unknown variable or function:z on line 3 of input044.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input046.c",
    "content": "* operator must be followed by an expression of pointer type on line 3 of input046.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input059.c",
    "content": "Unknown variable or function:y on line 3 of input059.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input060.c",
    "content": "Expression is not a struct/union on line 3 of input060.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input061.c",
    "content": "Expression is not a pointer to a struct/union on line 3 of input061.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input086.c",
    "content": "Function definition not at global level on line 2 of input086.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input093.c",
    "content": "Unknown variable or function:fred on line 1 of input093.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input124.c",
    "content": "Cannot ++ on rvalue on line 6 of input124.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input126.c",
    "content": "Unknown variable or function:ptr on line 7 of input126.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input129.c",
    "content": "Cannot ++ and/or -- more than once on line 6 of input129.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input141.c",
    "content": "Declaration of array parameters is not implemented on line 4 of input141.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/err.input142.c",
    "content": "Array must have non-zero elements:fred on line 1 of input142.c\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input122.c",
    "content": "#include <stdio.h>\n\nint x, y, z1, z2;\n\nint main() {\n  for (x= 0; x <= 1; x++) {\n    for (y= 0; y <= 1; y++) {\n      z1= x || y; z2= x && y;\n      printf(\"x %d, y %d, x || y %d, x && y %d\\n\", x, y, z1, z2);\n    }\n  }\n  \n  //z= x || y;\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input123.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  for (x=0; x < 20; x++)\n    switch(x) {\n      case 2:\n      case 3:\n      case 5:\n      case 7:\n      case 11: printf(\"%2d infant prime\\n\", x); break;\n      case 13:\n      case 17:\n      case 19: printf(\"%2d teen   prime\\n\", x); break;\n      case 0:\n      case 1:\n      case 4:\n      case 6:\n      case 8:\n      case 9:\n      case 10:\n      case 12: printf(\"%2d infant composite\\n\", x); break;\n      default: printf(\"%2d teen   composite\\n\", x); break;\n    }\n\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input124.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary++;\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input125.c",
    "content": "#include <stdio.h>\n\nint ary[5];\nint *ptr;\nint x;\n\nint main() {\n  ary[3]= 2008;\n  ptr= ary;\t\t\t// Load ary's address into ptr\n  x= ary[3]; printf(\"%d\\n\", x);\n  x= ptr[3]; printf(\"%d\\n\", x); // Treat ptr as an array\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input126.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary[3]= 2008;\n  ptr= &ary;\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input127.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nvoid fred(int *ptr) {\t\t// Receive a pointer\n  printf(\"%d\\n\", ptr[3]);\n}\n\nint main() {\n  ary[3]= 2008;\n  printf(\"%d\\n\", ary[3]);\n  fred(ary);\t\t\t// Pass ary as a pointer\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input128.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int val;\n  struct foo *next;\n};\n\nstruct foo head, mid, tail;\n\nint main() {\n  struct foo *ptr;\n  tail.val= 20; tail.next= NULL;\n  mid.val= 15; mid.next= &tail;\n  head.val= 10; head.next= &mid;\n\n  ptr= &head;\n  printf(\"%d %d\\n\", head.val, ptr->val);\n  printf(\"%d %d\\n\", mid.val, ptr->next->val);\n  printf(\"%d %d\\n\", tail.val, ptr->next->next->val);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input129.c",
    "content": "#include <stdio.h>\n\nint x= 6;\n\nint main() {\n  printf(\"%d\\n\", x++ ++);\n  return(0);\n}\n\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input130.c",
    "content": "#include <stdio.h>\n\nchar *x= \"foo\";\n\nint main() {\n  printf(\"Hello \" \"world\" \"\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input131.c",
    "content": "#include <stdio.h>\n\nvoid donothing() { }\n\nint main() {\n  int x=0;\n  printf(\"Doing nothing... \"); donothing();\n  printf(\"nothing done\\n\");\n\n  while (++x < 100) ;\n  printf(\"x is now %d\\n\", x);\n\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input132.c",
    "content": "extern int fred;\nint fred;\n\nint mary;\nextern int mary;\n\nint main() { return(0); }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input133.c",
    "content": "#include <stdio.h>\n\nextern int fred[];\nint fred[23];\n\nchar mary[100];\nextern char mary[];\n\nvoid main() { printf(\"OK\\n\"); }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input134.c",
    "content": "#include <stdio.h>\n\nchar y = 'a';\nchar *x;\n\nint main() {\n  x= &y;        if (x && y == 'a') printf(\"1st match\\n\");\n  x= NULL;      if (x && y == 'a') printf(\"2nd match\\n\");\n  x= &y; y='b'; if (x && y == 'a') printf(\"3rd match\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input135.c",
    "content": "#include <stdio.h>\n\nvoid fred() {\n  int x= 5;\n  printf(\"testing x\\n\");\n  if (x > 4) return;\n  printf(\"x below 5\\n\");\n}\n\nint main() {\n  fred();\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input136.c",
    "content": "#include <stdio.h>\n\nint add(int x, int y) {\n  return(x+y);\n}\n\nint main() {\n  int result;\n  result= 3 * add(2,3) - 5 * add(4,6);\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input137.c",
    "content": "#include <stdio.h>\n\nint a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8;\n\nint main() {\n  int x;\n  x= ((((((a + b) + c) + d) + e) + f) + g) + h;\n  x= a + (b + (c + (d + (e + (f + (g + h))))));\n  printf(\"x is %d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input138.c",
    "content": "#include <stdio.h>\n\nint x, y, z;\n\nint a=1;\nint *aptr;\n\nint main() {\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x && y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x || y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // Now some lazy evaluation\n  aptr= NULL;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  aptr= &a;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input139.c",
    "content": "#include <stdio.h>\n\nint same(int x) { return(x); }\n\nint main() {\n  int a= 3;\n\n  if (same(a) && same(a) >= same(a))\n    printf(\"same apparently\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input140.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int  i;\n  int  ary[5];\n  char z;\n\n  // Write below the array\n  z= 'H';\n\n  // Fill the array\n  for (i=0; i < 5; i++)\n    ary[i]= i * i;\n\n  // Write above the array\n  i=14;\n\n  // Print out the array\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", ary[i]);\n\n  // See if either side is OK\n  printf(\"%d %c\\n\", i, z);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input141.c",
    "content": "static int fred[5];\nint jim;\n\nint foo(int mary[6]) { return(5); }\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input142.c",
    "content": "static int fred[];\nint jim;\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input143.c",
    "content": "#include <stdio.h>\n\nchar foo;\nchar *a, *b, *c;\n\nint main() {\n\n  a= b= c= NULL;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  a= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  b= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  c= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  else\n    printf(\"All  three  are non-NULL\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input144.c",
    "content": "#include <stdio.h>\n#include <errno.h>\n#include <string.h>\nchar *filename= \"fred\";\nint main() {\n    fprintf(stdout, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input145.c",
    "content": "#include <stdio.h>\n\nchar *str= \"qwertyuiop\";\n\nint list[]= {3, 5, 7, 9, 11, 13, 15};\n\nint *lptr;\n\nint main() {\n  printf(\"%c\\n\", *str);\n  str= str + 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str -= 1; printf(\"%c\\n\", *str);\n\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input146.c",
    "content": "#include <stdio.h>\n\nchar *str= \"qwertyuiop\";\n\nint list[]= {3, 5, 7, 9, 11, 13, 15};\n\nint *lptr;\n\nint main() {\n  printf(\"%c\\n\", *str);\n  str= str + 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str -= 1; printf(\"%c\\n\", *str);\n  str++; printf(\"%c\\n\", *str);\n  str--; printf(\"%c\\n\", *str);\n  ++str; printf(\"%c\\n\", *str);\n  --str; printf(\"%c\\n\\n\", *str);\n\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  lptr++   ; printf(\"%d\\n\", *lptr);\n  lptr--   ; printf(\"%d\\n\", *lptr);\n  ++lptr   ; printf(\"%d\\n\", *lptr);\n  --lptr   ; printf(\"%d\\n\", *lptr);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input147.c",
    "content": "#include <stdio.h>\n\nint a;\n\nint main() {\n  printf(\"%d\\n\", 24 % 9);\n  printf(\"%d\\n\", 31 % 11);\n  a= 24; a %= 9; printf(\"%d\\n\",a);\n  a= 31; a %= 11; printf(\"%d\\n\",a);\n  return(0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/input148.c",
    "content": "#include <stdio.h>\n\nchar *argv[]= { \"unused\", \"-fish\", \"-cat\", \"owl\" };\nint argc= 4;\n\nint main() {\n  int i;\n\n  for (i = 1; i < argc; i++) {\n    printf(\"i is %d\\n\", i);\n    if (*argv[i] != '-') break;\n  }\n\n  while (i < argc) {\n    printf(\"leftover %s\\n\", argv[i]);\n    i++;\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "59_WDIW_pt1/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input122.c",
    "content": "x 0, y 0, x || y 0, x && y 0\nx 0, y 1, x || y 1, x && y 0\nx 1, y 0, x || y 1, x && y 0\nx 1, y 1, x || y 1, x && y 1\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input123.c",
    "content": " 0 infant composite\n 1 infant composite\n 2 infant prime\n 3 infant prime\n 4 infant composite\n 5 infant prime\n 6 infant composite\n 7 infant prime\n 8 infant composite\n 9 infant composite\n10 infant composite\n11 infant prime\n12 infant composite\n13 teen   prime\n14 teen   composite\n15 teen   composite\n16 teen   composite\n17 teen   prime\n18 teen   composite\n19 teen   prime\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input125.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input127.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input128.c",
    "content": "10 10\n15 15\n20 20\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input130.c",
    "content": "Hello world\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input131.c",
    "content": "Doing nothing... nothing done\nx is now 100\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input132.c",
    "content": ""
  },
  {
    "path": "59_WDIW_pt1/tests/out.input133.c",
    "content": "OK\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input134.c",
    "content": "1st match\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input135.c",
    "content": "testing x\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input136.c",
    "content": "-35\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input137.c",
    "content": "x is 36\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input138.c",
    "content": "0 0 | 0\n0 1 | 0\n1 0 | 0\n1 1 | 1\n0 0 | 0\n0 1 | 1\n1 0 | 1\n1 1 | 1\naptr is NULL or doesn't point at 1\naptr points at 1\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input139.c",
    "content": "same apparently\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input140.c",
    "content": "0\n1\n4\n9\n16\n5 H\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input143.c",
    "content": "One of the three is NULL\nOne of the three is NULL\nOne of the three is NULL\nAll  three  are non-NULL\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input144.c",
    "content": "Unable to open fred: Success\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input145.c",
    "content": "q\nw\ne\nr\ne\n3\n5\n7\n9\n7\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input146.c",
    "content": "q\nw\ne\nr\ne\nr\ne\nr\ne\n\n3\n5\n7\n9\n7\n9\n7\n9\n7\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input147.c",
    "content": "6\n9\n6\n9\n"
  },
  {
    "path": "59_WDIW_pt1/tests/out.input148.c",
    "content": "i is 1\ni is 2\ni is 3\nleftover owl\n"
  },
  {
    "path": "59_WDIW_pt1/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "59_WDIW_pt1/tests/runtests0",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install; make cwj0)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj0 -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj0 $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "59_WDIW_pt1/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo \n   bn=$(echo $i | cut -d. -f1)\n   if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s ${bn}.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "59_WDIW_pt1/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->ctype = ctype;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  n->linenum= 0;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n  int i;\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    case A_TOBOOL:\n      fprintf(stdout, \"A_TOBOOL\\n\");\n      return;\n    case A_LOGOR:\n      fprintf(stdout, \"A_LOGOR\\n\");\n      return;\n    case A_LOGAND:\n      fprintf(stdout, \"A_LOGAND\\n\");\n      return;\n    case A_AND:\n      fprintf(stdout, \"A_AND\\n\");\n      return;\n    case A_ASMOD:\n      fprintf(stdout, \"A_ASMOD\\n\");\n      return;\n    case A_INVERT:\n      fprintf(stdout, \"A_INVERT\\n\");\n      return;\n    case A_LOGNOT:\n      fprintf(stdout, \"A_LOGNOT\\n\");\n      return;\n    case A_LSHIFT:\n      fprintf(stdout, \"A_LSHIFT\\n\");\n      return;\n    case A_MOD:\n      fprintf(stdout, \"A_MOD\\n\");\n      return;\n    case A_OR:\n      fprintf(stdout, \"A_OR\\n\");\n      return;\n    case A_RSHIFT:\n      fprintf(stdout, \"A_RSHIFT\\n\");\n      return;\n    case A_TERNARY:\n      fprintf(stdout, \"A_TERNARY\\n\");\n      return;\n    case A_XOR:\n      fprintf(stdout, \"A_XOR\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "59_WDIW_pt1/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n\t\t\t    struct symtable *rctype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // For A_LOGOR and A_LOGAND, both types have to be int or pointer types\n  if (op==A_LOGOR || op==A_LOGAND) {\n    if (!inttype(ltype) && !ptrtype(ltype))\n      return(NULL);\n    if (!inttype(ltype) && !ptrtype(rtype))\n      return(NULL);\n    return (tree);\n  }\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, NULL, tree, NULL, 0));\n  }\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return (tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n  // We can scale only on add and subtract operations\n  if (op == A_ADD || op == A_SUBTRACT ||\n      op == A_ASPLUS || op == A_ASMINUS) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, rctype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "60_TripleTest/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h incdir.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\techo \"#define INCDIR \\\"$(INCDIR)\\\"\" > incdir.h\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\techo \"#define __NASM__ 1\" >> incdir.h\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\techo \"#define INCDIR \\\"$(INCDIR)\\\"\" > incdir.h\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\nincdir.h:\n\techo \"#define INCDIR \\\"$(INCDIR)\\\"\" > incdir.h\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwj[0-9] cwjarm compn compn[0-9] *.o *.s out a.out incdir.h\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\n# Run the tests with the\n# compiler that compiled itself\ntest0: install tests/runtests0 cwj0\n\t(cd tests; chmod +x runtests0; ./runtests0)\n\n# Run the tests with the\n# compiler that compiled itself\ntest0n: install tests/runtests0n compn0\n\t(cd tests; chmod +x runtests0n; ./runtests0n)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\n# Try to do the triple test\ntriple: cwj1\n\tsize cwj[01]\n\n# Paranoid: quadruple test\nquad: cwj2\n\tsize cwj[012]\n\ncwj2: cwj1 $(SRCS) $(HSRCS)\n\t./cwj1 -o cwj2 $(SRCS)\n\ncwj1: cwj0 $(SRCS) $(HSRCS)\n\t./cwj0 -o cwj1 $(SRCS)\n\ncwj0: install $(SRCS) $(HSRCS)\n\t./cwj  -o cwj0 $(SRCS)\n\n# Try to do the triple test with nasm\ntriplen: compn1\n\tsize compn[01]\n\nquadn: compn2\n\tsize compn[012]\n\ncompn2: compn1 $(SRCN) $(HSRCS)\n\t./compn1 -o compn2 $(SRCN)\n\ncompn1: compn0 $(SRCN) $(HSRCS)\n\t./compn0 -o compn1 $(SRCN)\n\ncompn0: installn $(SRCN) $(HSRCS)\n\techo \"#define __NASM__ 1\" >> incdir.h\n\t./compn  -o compn0 $(SRCN)\n"
  },
  {
    "path": "60_TripleTest/Readme.md",
    "content": "# Part 60: Passing the Triple Test\n\nIn this part of our compiler writing journey, we will\nget the compiler to pass the triple test! How do I know?\nI've just got it to pass the triple test by changing\na few source code lines in the compiler. But I don't\nyet know why the original lines are not working.\n\nSo, this part will be a investigation where we gather the\nclues, deduce the problem, fix it and finally get the\ncompiler to pass the triple test properly.\n\nOr, so I hope!\n\n## The First Piece of Evidence\n\nWe now have three compiler binaries:\n\n  1. `cwj`, built with the Gnu C compiler,\n  2. `cwj0`, built with the `cwj` compiler, and\n  2. `cwj1`, built with the `cwj0` compiler\n\nThe last two should be identical but they are not. Thus, `cwj0`\nisn't generating the right assembly output, and this is because\nof a flaw in the compiler's source code.\n\nHow can we narrow the problem down? Well, we have a pile of\ntest programs in the `tests/` directory. Let's run `cwj` and\n`cwj0` over all these tests and see if there's a difference.\n\nYes there is, with `tests/input002.c`:\n\n```\n$ ./cwj -o z tests/input002.c ; ./z\n17\n$ ./cwj0 -o z tests/input002.c ; ./z\n24\n```\n\n## What's The Problem?\n\nSo, `cwj0` is producing incorrect assembly output. Let's start \nwith the test source code:\n\n```c\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n```\n\nWe have two local variables, `fred` and `jim`. The two compilers\nproduce assembly code with these differences:\n\n```\n42c42\n<       movl    %r10d, -4(%rbp)\n---\n>       movl    %r10d, -8(%rbp)\n51c51\n<       movslq  -4(%rbp), %r10\n---\n>       movslq  -8(%rbp), %r10\n```\n\nHmm, the second compiler is calculating the offset of `fred`\nincorrectly. The first compiler is correctly calculating the\noffset as `-4` below the frame pointer. The second compiler\nis calculating the offset as `-8` below the frame pointer.\n\n## What's Causing the Problem?\n\nThese offsets are being calculated by the function\n`newlocaloffset()` in `cg.c`:\n\n```c\n// Create the position of a new local variable.\nstatic int localOffset;\nstatic int newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n```\n\nAt the start of each function, `localOffset` is set to zero.\nAs we create local variables, we get the size of each one,\npass it to `newlocaloffset()` and get back the offset.\n\nBoth `fred` and `jim` local variables are `int`s, which are\nsize 4. Therefore, their offsets should be `-4` and `-8`.\n\n## More Evidence, Please\n\nLet's abstract  `newlocaloffset()` into a separate source\nfile, `z.c` (my \"go to\" temporary file name) and compile it.\nThe source file is:\n\n```c\nstatic int localOffset=0;\nstatic int newlocaloffset(int size) {\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n```\n\nAnd here is the output assembly with my comments:\n\n```\n        .data\nlocalOffset:\n        .long   0\n        \n        .text\nnewlocaloffset:\n        pushq   %rbp                     \n        movq    %rsp, %rbp               # Set up the stack and\n        movl    %edi, -4(%rbp)           # frame pointers\n        addq    $-16,%rsp               \n        movslq  localOffset(%rip), %r10  # Get localOffset into %r10\n                                         # in preparation for the +=\n        movslq  -4(%rbp), %r11           # Get size into %r11\n        movq    $4, %r12                 # Get  4   into %r12\n        cmpl    %r12d, %r11d             # Compare them\n        jle     L2                       # Jump if size < 4\n        movslq  -4(%rbp), %r11\n        movq    %r11, %r10               # Get size into %r10\n        jmp     L3                       # and jump to L3\nL2:\n        movq    $4, %r11                 # Otherwise get 4\n        movq    %r11, %r10               # into %r10\nL3:\n        addq    %r10, %r10               # Add the += exression to the\n                                         # cached copy of localOffset\n        movl    %r10d, localOffset(%rip) # Save %r10 into localOffset\n        movslq  localOffset(%rip), %r10\n        negq    %r10                     # Negate localOffset\n        movl    %r10d, %eax              # Set up the return value\n        jmp     L1                      \nL1:\n        addq    $16,%rsp                 # Restore the stack and\n        popq    %rbp                     # frame pointers\n        ret                              # and return\n```\n\nHmm, the code is trying to do `localOffset += expression`,\nand we have a copy of `localOffset` cached in `%r10`.\nHowever, the expression itself also uses `%r10`, thus\ndestroying the cached version of `localOffset`.\n\nThe `addq %r10, %r10`, in particular, is just wrong:\nit should be adding two different registers.\n\n## Passing the Triple Test by Cheating\n\nWe can pass the triple test by rewriting the source code\nto `newlocaloffset()`:\n\n```c\nstatic int newlocaloffset(int size) {\n  if (size > 4)\n    localOffset= localOffset + size;\n  else\n    localOffset= localOffset + 4;\n  return (-localOffset);\n}\n```\n\nWhen we now do:\n\n```\n$ make triple\ncc -Wall -o cwj  cg.c decl.c expr.c gen.c main.c misc.c opt.c scan.c stmt.c sym.c tree.c types.c\n./cwj    -o cwj0 cg.c decl.c expr.c gen.c main.c misc.c opt.c scan.c stmt.c sym.c tree.c types.c\n./cwj0   -o cwj1 cg.c decl.c expr.c gen.c main.c misc.c opt.c scan.c stmt.c sym.c tree.c types.c\nsize cwj[01]\n   text    data     bss     dec     hex filename\n 109652    3028      48  112728   1b858 cwj0\n 109652    3028      48  112728   1b858 cwj1\n```\n\nthe last two compiler binaries are 100% identical. But this hides\nthe fact that the original `newlocaloffset()` source code should\nwork but it doesn't.\n\nWhy are we reallocating `%r10` when we know that it is allocated?\n\n## A Possible Culprit\n\nI added back in to `cg.c` the `printf()` lines to see when registers\nwere being allocated and freed. I noticed that, after these assembly\nlines:\n\n```\n        movslq  -4(%rbp), %r11           # Get size into %r11\n        movq    $4, %r12                 # Get  4   into %r12\n        cmpl    %r12d, %r11d             # Compare them\n        jle     L2                       # Jump if size < 4\n```\n\nall the registers are freed, even though `%r10` holds the cached\ncopy of `localOffset`. Which function is generating these lines\nand freeing the registers? The answer is:\n\n```c\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label, int type) {\n  int size = cgprimsize(type);\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tcmpb\\t%s, %s\\n\", breglist[r2], breglist[r1]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tcmpl\\t%s, %s\\n\", dreglist[r2], dreglist[r1]);\n    break;\n  default:\n    fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  }\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  freeall_registers(NOREG);\n  return (NOREG);\n}\n```\n\nLooking at the code, we can definitely free `r1` and `r2`, so let's\ntry that instead of freeing all the registers.\n\nYes, that helps, and all our regression tests still pass.\nHowever, another function is also freeing all the registers.\nIt's time to use `gdb` and follow the execution.\n\n## The Real Culprit\n\nIt looks like the real culprit is that I forgot that many operations\ncan be part of an expression, and I can't free all registers until\nthe expression's result is either used or discarded.\n\nAs I looked at the execution with `gdb`, I saw that the code that\ndeals with ternary operators is freeing registers, even though\nthis may only be part of a bigger expression with registers already\nallocated (in `gen.c`):\n\n```c\nstatic int gen_ternary(struct ASTnode *n) {\n  ...\n  // Generate the condition code\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);           // HERE\n\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  // Don't free the register holding the result, though!\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  genfreeregs(reg);             // HERE\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  // Don't free the register holding the result, though!\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  genfreeregs(reg);             // HERE\n  ...\n}\n```\n\nLooking through `cg.c`, all the functions in there free registers\nthat are no longer used, so I think that we can lose the `genfreeregs()`\nstraight after the generation of the condition code.\n\nNext up, once we move the true expression's value in the register\nreserved for the ternary result, we can free `expreg`. Ditto for the\nfalse expression's value.\n\nTo make this happen, I've made a previously-static function in `cg.c`\nglobal and renamed it:\n\n```c\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nvoid cgfreereg(int reg) { ... }\n```\n\nWe can now rewrite the ternary handling code in `gen.c`:\n\n```c\nstatic int gen_ternary(struct ASTnode *n) {\n  ...\n    // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  cgfreereg(expreg);\n  ...\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  cgfreereg(expreg);\n  ...\n}\n```\n\nWith this change, the compiler now passes several tests:\n\n  + the triple test: `$ make triple`\n  + a quadruple test where we do one more compiler compilation:\n\n```\n$ make quad\n...\n./cwj  -o cwj0 cg.c decl.c expr.c gen.c main.c misc.c opt.c scan.c stmt.c sym.c tree.c types.c\n./cwj0 -o cwj1 cg.c decl.c expr.c gen.c main.c misc.c opt.c scan.c stmt.c sym.c tree.c types.c\n./cwj1 -o cwj2 cg.c decl.c expr.c gen.c main.c misc.c opt.c scan.c stmt.c sym.c tree.c types.c\nsize cwj[012]\n   text    data     bss     dec     hex filename\n 109636    3028      48  112712   1b848 cwj0\n 109636    3028      48  112712   1b848 cwj1\n 109636    3028      48  112712   1b848 cwj2\n```\n\n  + the regression tests with the Gnu C compiled compiler: `$ make test`\n  + the regression tests with our compiler compiled with itself: `$ make test0`\n  \nThat feels very satisfying.\n\n## Conclusion and What's Next\n\nI've reached the original goal of this journey: to write a\nself-compiling compiler. It's taken 60 parts, 5,700 lines of\ncode, 149 regression tests and 108,000 words in the *Readme* files.\n\nThat said, this doesn't have to be the end of the journey. There is\nstill a lot of work that could be done to the compiler to make it\nmore production ready. However, I've been working sporadically on this\nfor about two months now, so I feel like I can (at least) have a small\nbreak.\n\nIn the next part of our compiler writing journey, I will outline what\nmore can be done with our compiler. Perhaps I'll do some of these\nthings; perhaps you will. [Next step](../61_What_Next/Readme.md)\n"
  },
  {
    "path": "60_TripleTest/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n  case P_CHAR:\n    return (1);\n  case P_INT:\n    return (4);\n  case P_LONG:\n    return (8);\n  default:\n    fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n  case P_CHAR:\n    return (offset);\n  case P_INT:\n  case P_LONG:\n    break;\n  default:\n    if (!ptrtype(type))\n      fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpopq\\t%s\\n\", reglist[r]);\n}\n\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\nvoid freeall_registers(int keepreg) {\n  int i;\n  // fprintf(Outfile, \"# freeing all registers\\n\");\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg = 0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      // fprintf(Outfile, \"# allocated register %s\\n\", reglist[reg]);\n      return (reg);\n    }\n  }\n\n  // We have no registers, so we must spill one\n  reg = (spillreg % NUMFREEREGS);\n  spillreg++;\n  // fprintf(Outfile, \"# spilling reg %s\\n\", reglist[reg]);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nvoid cgfreereg(int reg) {\n  if (freereg[reg] != 0) {\n    // fprintf(Outfile, \"# error trying to free register %s\\n\", reglist[reg]);\n    fatald(\"Error trying to free register\", reg);\n  }\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg = (spillreg % NUMFREEREGS);\n    // fprintf(Outfile, \"# unspilling reg %s\\n\", reglist[reg]);\n    popreg(reg);\n  } else {\n    // fprintf(Outfile, \"# freeing reg %s\\n\", reglist[reg]);\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid spill_all_regs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void unspill_all_regs(void) {\n  int i;\n\n  for (i = NUMFREEREGS - 1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble(char *filename) {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile, \"\\t.file 1 \");\n  fputc('\"', Outfile);\n  fprintf(Outfile, \"%s\", filename);\n  fputc('\"', Outfile);\n  fputc('\\n', Outfile);\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"__switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"__next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     __no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"__no:\\n\"\n\t  \"        loop    __next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\" \"\\t.type\\t%s, @function\\n\", name, name);\n  fprintf(Outfile, \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\" \"\\tmovq\\t%%rsp, %%rbp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->size);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n  freeall_registers(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadvar(struct symtable *sym, int op) {\n  int r, postreg, offset = 1;\n\n  // Get a new register\n  r = alloc_register();\n\n  // If the symbol is a pointer, use the size\n  // of the type that it points to as any\n  // increment or decrement. If not, it's one.\n  if (ptrtype(sym->type))\n    offset = typesize(value_at(sym->type), sym->ctype);\n\n  // Negate the offset for decrements\n  if (op == A_PREDEC || op == A_POSTDEC)\n    offset = -offset;\n\n  // If we have a pre-operation\n  if (op == A_PREINC || op == A_PREDEC) {\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    else\n      fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\n    // and change the value at that address\n    switch (sym->size) {\n    case 1:\n      fprintf(Outfile, \"\\taddb\\t$%d,(%s)\\n\", offset, reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\taddl\\t$%d,(%s)\\n\", offset, reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\taddq\\t$%d,(%s)\\n\", offset, reglist[r]);\n      break;\n    }\n  }\n  // Now load the output register with the value\n  if (sym->class == C_LOCAL || sym->class == C_PARAM) {\n    switch (sym->size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    }\n  } else {\n    switch (sym->size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    }\n  }\n\n  // If we have a post-operation, get a new register\n  if (op == A_POSTINC || op == A_POSTDEC) {\n    postreg = alloc_register();\n\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn,\n\t      reglist[postreg]);\n    else\n      fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name,\n\t      reglist[postreg]);\n    // and change the value at that address\n\n    switch (sym->size) {\n    case 1:\n      fprintf(Outfile, \"\\taddb\\t$%d,(%s)\\n\", offset, reglist[postreg]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\taddl\\t$%d,(%s)\\n\", offset, reglist[postreg]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\taddq\\t$%d,(%s)\\n\", offset, reglist[postreg]);\n      break;\n    }\n    // and free the register\n    cgfreereg(postreg);\n  }\n  // Return the register with the value\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Divide or modulo the first register by the second and\n// return the number of the register with the result\nint cgdivmod(int r1, int r2, int op) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  if (op == A_DIVIDE)\n    fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  else\n    fprintf(Outfile, \"\\tmovq\\t%%rdx,%s\\n\", reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", val, reglist[r]);\n}\n\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch (op) {\n  case A_IF:\n  case A_WHILE:\n  case A_LOGAND:\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n    break;\n  case A_LOGOR:\n    fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n    break;\n  default:\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n\n  // Unspill all the registers\n  unspill_all_regs();\n\n  // Get a new register and copy the return value into it\n  outr = alloc_register();\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n  cgfreereg(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->st_posn);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n      break;\n    case 8:\n      // Generate the pointer to a string literal. Treat a zero value\n      // as actually zero, not the label L0\n      if (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t  && initvalue != 0)\n\tfprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n      else\n\tfprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n      break;\n    default:\n      for (i = 0; i < size; i++)\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2, int type) {\n  int size = cgprimsize(type);\n\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tcmpb\\t%s, %s\\n\", breglist[r2], breglist[r1]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tcmpl\\t%s, %s\\n\", dreglist[r2], dreglist[r1]);\n    break;\n  default:\n    fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  }\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  cgfreereg(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label, int type) {\n  int size = cgprimsize(type);\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tcmpb\\t%s, %s\\n\", breglist[r2], breglist[r1]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tcmpl\\t%s, %s\\n\", dreglist[r2], dreglist[r1]);\n    break;\n  default:\n    fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  }\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  cgfreereg(r1);\n  cgfreereg(r2);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n\tbreak;\n      case P_LONG:\n\tfprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n\tbreak;\n      default:\n\tfatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n\n  cgjump(sym->st_endlabel);\n}\n\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (sym->class == C_GLOBAL ||\n      sym->class == C_EXTERN || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  default:\n    fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tmovl\\t%s, (%s)\\n\", dreglist[r1], reglist[r2]);\n    break;\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\t__switch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n}\n\nvoid cglinenum(int line) {\n  fprintf(Outfile, \"\\t.loc 1 %d 0\\n\", line);\n}\n"
  },
  {
    "path": "60_TripleTest/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "60_TripleTest/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      return (offset);\n    case P_INT:\n    case P_LONG:\n      break;\n    default:\n      if (!ptrtype(type))\n        fatald(\"Bad type in cg_align:\", type);\n  }\n\n  // Here we have an int or a long. Align it on a 4-byte offset\n  // I put the generic code here so it can be reused elsewhere.\n  alignment = 4;\n  offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n   \"rdi\"\n};\nstatic char *breglist[] =\n { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n   \"dil\"\n};\nstatic char *dreglist[] =\n { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n  \"esi\", \"edi\"\n};\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpop\\t%s\\n\", reglist[r]);\n}\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\n\nvoid freeall_registers(int keepreg) {\n  int i;\n  // fprintf(Outfile, \"; freeing all registers\\n\");\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg = 0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint alloc_register(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      // fprintf(Outfile, \"; allocated register %s\\n\", reglist[reg]);\n      return (reg);\n    }\n  }\n  // We have no registers, so we must spill one\n  reg = (spillreg % NUMFREEREGS);\n  spillreg++;\n  // fprintf(Outfile, \"; spilling reg %s\\n\", reglist[reg]);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nvoid cgfreereg(int reg) {\n  if (freereg[reg] != 0) {\n    //fprintf(Outfile, \"# error trying to free register %s\\n\", reglist[reg]);\n    fatald(\"Error trying to free register\", reg);\n  }\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg = (spillreg % NUMFREEREGS);\n    // fprintf(Outfile, \"; unspilling reg %s\\n\", reglist[reg]);\n    popreg(reg);\n  } else {\n    // fprintf(Outfile, \"; freeing reg %s\\n\", reglist[reg]);\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid spill_all_regs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void unspill_all_regs(void) {\n  int i;\n\n  for (i = NUMFREEREGS - 1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble(char *filename) {\n  freeall_registers(NOREG);\n  cgtextseg();\n  fprintf(Outfile, \";\\t%s\\n\", filename);\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"__switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"__next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    __no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"__no:\\n\"\n\t  \"        loop   __next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\\n\");\n}\n\n// Nothing to do\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n//  if (sym->class == C_GLOBAL)\n  if(!sym->extinit) {\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", name);\n    sym->extinit = 1;\n  }\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->size);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n  freeall_registers(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadvar(struct symtable *sym, int op) {\n  int r, postreg, offset = 1;\n\n  if(!sym->extinit) {\n    fprintf(Outfile, \"extern\\t%s\\n\", sym->name);\n    sym->extinit = 1;\n  }\n\n  // Get a new register\n  r = alloc_register();\n\n  // If the symbol is a pointer, use the size\n  // of the type that it points to as any\n  // increment or decrement. If not, it's one.\n  if (ptrtype(sym->type))\n    offset = typesize(value_at(sym->type), sym->ctype);\n\n  // Negate the offset for decrements\n  if (op == A_PREDEC || op == A_POSTDEC)\n    offset = -offset;\n\n  // If we have a pre-operation\n  if (op == A_PREINC || op == A_PREDEC) {\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r], sym->st_posn);\n    else\n      fprintf(Outfile, \"\\tlea\\t%s, [%s]\\n\", reglist[r], sym->name);\n\n    // and change the value at that address\n    switch (sym->size) {\n      case 1:\n        fprintf(Outfile, \"\\tadd\\tbyte [%s], %d\\n\", reglist[r], offset);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tadd\\tdword [%s], %d\\n\", reglist[r], offset);\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tadd\\tqword [%s], %d\\n\", reglist[r], offset);\n        break;\n    }\n  }\n\n  // Now load the output register with the value\n  if (sym->class == C_LOCAL || sym->class == C_PARAM) {\n    switch (sym->size) {\n      case 1:\n        fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], sym->st_posn);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tmovsxd\\t%s, dword [rbp+%d]\\n\", reglist[r], sym->st_posn);\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r], sym->st_posn);\n    }\n  } else {\n    switch (sym->size) {\n      case 1:\n        fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], sym->name);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tmovsxd\\t%s, dword [%s]\\n\", reglist[r], sym->name);\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    }\n  }\n\n  // If we have a post-operation, get a new register\n  if (op == A_POSTINC || op == A_POSTDEC) {\n    postreg = alloc_register();\n\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[postreg], sym->st_posn);\n    else\n      fprintf(Outfile, \"\\tlea\\t%s, [%s]\\n\", reglist[postreg], sym->name);\n    // and change the value at that address\n\n    switch (sym->size) {\n      case 1:\n        fprintf(Outfile, \"\\tadd\\tbyte [%s], %d\\n\", reglist[postreg], offset);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tadd\\tdword [%s], %d\\n\", reglist[postreg], offset);\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tadd\\tqword [%s], %d\\n\", reglist[postreg], offset);\n        break;\n    }\n    // and free the register\n    cgfreereg(postreg);\n  }\n\n  // Return the register with the value\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Divide or modulo the first register by the second and\n// return the number of the register with the result\nint cgdivmod(int r1, int r2, int op) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  if (op == A_DIVIDE)\n    fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  else\n    fprintf(Outfile, \"\\tmov\\t%s, rdx\\n\", reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  cgfreereg(r2);\n  return (r1);\n}\n\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  cgfreereg(r2);\n  return (r1);\n}\n\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  cgfreereg(r2);\n  return (r1);\n}\n\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], val);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch (op) {\n    case A_IF:\n    case A_WHILE:\n    case A_LOGAND:\n      fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n      break;\n    case A_LOGOR:\n      fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n      break;\n    default:\n      fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id\n// Pop off any arguments pushed on the stack\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  if(!sym->extinit) {\n    fprintf(Outfile, \"extern\\t%s\\n\", sym->name);\n    sym->extinit = 1;\n  }\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n  // Unspill all the registers\n  unspill_all_regs();\n  // Get a new register and copy the return value into it\n  outr = alloc_register();\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function\n// call. Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n  cgfreereg(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if(!sym->extinit) {\n    fprintf(Outfile, \"extern\\t%s\\n\", sym->name);\n    sym->extinit = 1;\n  }\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", node->name);\n  if(!node->extinit) {\n    node->extinit = 1;\n  }\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n    }\n  }\n\n}\n\n// Generate a global string and its start label\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n}\n\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2, int type) {\n  int size = cgprimsize(type);\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", breglist[r1], breglist[r2]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", dreglist[r1], dreglist[r2]);\n      break;\n    default:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  }\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  cgfreereg(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label, int type) {\n  int size = cgprimsize(type);\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", breglist[r1], breglist[r2]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", dreglist[r1], dreglist[r2]);\n      break;\n    default:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  }\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  cgfreereg(r1);\n  cgfreereg(r2);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n        case P_CHAR:\n          fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n          break;\n        case P_INT:\n          fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n          break;\n        case P_LONG:\n          fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n          break;\n        default:\n          fatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = alloc_register();\n\n  if (!sym->extinit) {\n    fprintf(Outfile, \"extern\\t%s\\n\", sym->name);\n    sym->extinit = 1;\n  }\n\n  if (sym->class == C_GLOBAL ||\n      sym->class == C_EXTERN || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmov\\t[%s], dword %s\\n\", reglist[r2], dreglist[r1]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\t__switch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n}\n\nvoid cglinenum(int line) {\n  //fprintf(Outfile, \";\\t.loc 1 %d 0\\n\", line);\n}\n"
  },
  {
    "path": "60_TripleTest/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Linestart;\t\t     \t// True if at start of a line\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\nextern char *Tstring[];\t\t\t// List of token strings\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_dumpsym;\t\t// If true, dump the symbol table\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "60_TripleTest/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Get the type inside the parentheses\n  type = parse_stars(parse_type(ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return (type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree = optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type = tree->type;\n    tree = tree->left;\n  }\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return (tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue == 0)\n      return (0);\n  }\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return (tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a pointer to a symbol that may already exist\n// return true if this symbol doesn't exist. We use\n// this function to convert externs into globals\nint is_new_symbol(struct symtable *sym, int class, \n\t\t  int type, struct symtable *ctype) {\n\n  // There is no existing symbol, thus is new\n  if (sym==NULL) return(1);\n\n  // global versus extern: if they match that it's not new\n  // and we can convert the class to global\n  if ((sym->class== C_GLOBAL && class== C_EXTERN)\n      || (sym->class== C_EXTERN && class== C_GLOBAL)) {\n\n      // If the types don't match, there's a problem\n      if (type != sym->type)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // Struct/unions, also compare the ctype\n      if (type >= P_STRUCT && ctype != sym->ctype)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // If we get to here, the types match, so mark the symbol\n      // as global\n      sym->class= C_GLOBAL;\n      // Return that symbol is not new\n      return(0);\n  }\n\n  // It must be a duplicate symbol if we get here\n  fatals(\"Duplicate global variable declaration\", sym->name);\n  return(-1);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree = NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, type, ctype))\n        sym = addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym = addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym = addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist = (int *) malloc(sizeof(int));\n      sym->initlist[0] = parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym->ctype, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, varnode->ctype, 0);\n      if (exprnode == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode->ctype, exprnode,\n\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t\t// New symbol table entry\n  int nelems = -1;\t\t// Assume the number of elements won't be given\n  int maxelems;\t\t\t// The maximum number of elements in the init list\n  int *initlist;\t\t// The list of initial elements \n  int i = 0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems = parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, pointer_to(type), ctype))\n        sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class, 0, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, pointer_to(type), ctype, S_ARRAY, 0);\n      break;\n    default:\n      fatal(\"Declaration of array parameters is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems = nelems;\n    else\n      maxelems = TABLE_INCREMENT;\n    initlist = (int *) malloc(maxelems * sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n\tfatal(\"Too many values in initialisation list\");\n\n      initlist[i++] = parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n\tmaxelems += TABLE_INCREMENT;\n\tinitlist = (int *) realloc(initlist, maxelems * sizeof(int));\n      }\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n\tscan(&Token);\n\tbreak;\n      }\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j = i; j < sym->nelems; j++)\n      initlist[j] = 0;\n    if (i > nelems)\n      nelems = i;\n    sym->initlist = initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  // Only externs can have no elements.\n  if (class != C_EXTERN && nelems<=0)\n    fatals(\"Array must have non-zero elements\", sym->name);\n\n  sym->nelems = nelems;\n  sym->size = sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n\tparamcnt = 0;\n\tscan(&Token);\n\tbreak;\n      }\n    }\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n  int linenum= Line;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumtion: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // Declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ..\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, ctype, tree, oldfuncsym, endlabel);\n  tree->linenum= linenum;\n\n  // Do optimisations on the AST tree\n  tree = optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated\n  // with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t = declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t == -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead == NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name = NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the variable's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET) {\n    sym = array_declaration(varname, type, ctype, class);\n    *tree= NULL;\t// Local arrays are not initialised\n  } else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree = NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n\tfatal(\"Function definition not at global level\");\n      return (type);\n    }\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree == NULL)\n      *gluetree = tree;\n    else\n      *gluetree =\n\tmkastnode(A_GLUE, P_NONE, NULL, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n  return(0);\t// Keep -Wall happy\n}\n\n// Parse one or more global declarations, either\n// variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype= NULL;\n  struct ASTnode *unused;\n\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n    // Skip any semicolons and right curly brackets\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "60_TripleTest/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int level);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop);\nvoid genpreamble(char *filename);\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue, int append);\nvoid genglobstrend(void);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nint alloc_register(void);\nvoid freeall_registers(int keepreg);\nvoid cgfreereg(int reg);\nvoid spill_all_regs(void);\nvoid cgpreamble(char *filename);\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadvar(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdivmod(int r1, int r2, int op);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue, int append);\nvoid cgglobstrend(void);\nint cgcompare_and_set(int ASTop, int r1, int r2, int type);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label, int type);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nvoid cgloadboolean(int r, int val);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\tint *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2);\nvoid cglinenum(int line);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype, int stype, int class,\n\t\t\tint nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype, int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype, int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype, int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\nvoid dumptable(struct symtable *head, char *name, int indent);\nvoid dumpsymtables(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(struct symtable **ctype);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n                            struct symtable *rctype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "60_TripleTest/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n#include \"incdir.h\"\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -g -f elf64 -w-ptr -o \"\n#define LDCMD \"cc -g -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -g -o \"\n#define LDCMD \"cc -g -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH, T_ASMOD,\n  T_QUESTION, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH, T_MOD,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR,\t\t\t//  1\n  A_ASSLASH, A_ASMOD, A_TERNARY, A_LOGOR,\t\t\t//  5\n  A_LOGAND, A_OR, A_XOR, A_AND, A_EQ, A_NE, A_LT,\t\t//  9\n  A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\t\t\t\t// 16\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_MOD,\t\t// 21\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\t\t\t\t// 26\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\t\t\t// 30\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\t\t\t\t// 35\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\t\t\t// 39\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\t\t// 43\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\t\t// 48\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n#ifdef __NASM__\n  int extinit;\n#endif\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n  int linenum;\t\t\t// Line number from where this node comes\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "60_TripleTest/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree =\n      mkastnode(A_GLUE, P_NONE, NULL, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree =\n    mkastunary(A_FUNCCALL, funcptr->type, funcptr->ctype, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(struct ASTnode *left) {\n  struct ASTnode *right;\n\n  // Check that the sub-tree is a pointer\n  if (!ptrtype(left->type))\n    fatal(\"Not an array or pointer\");\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, left->ctype, A_ADD);\n\n  // Return an AST tree where the array's base has the offset added to it,\n  // and dereference the element. Still an lvalue at this point.\n  left =\n    mkastnode(A_ADD, left->type, left->ctype, left, NULL, right, NULL, 0);\n  left =\n    mkastunary(A_DEREF, value_at(left->type), left->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(struct ASTnode *left, int withpointer) {\n  struct ASTnode *right;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the left AST tree is a pointer to struct or union\n  if (withpointer && left->type != pointer_to(P_STRUCT)\n      && left->type != pointer_to(P_UNION))\n    fatal(\"Expression is not a pointer to a struct/union\");\n\n  // Or, check that the left AST tree is a struct or union.\n  // If so, change it from an A_IDENT to an A_ADDR so that\n  // we get the base address, not the value at this address.\n  if (!withpointer) {\n    if (left->type == P_STRUCT || left->type == P_UNION)\n      left->op = A_ADDR;\n    else\n      fatal(\"Expression is not a struct/union\");\n  }\n\n  // Get the details of the composite type\n  typeptr = left->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left =\n    mkastnode(A_ADD, pointer_to(m->type), m->ctype, left, NULL, right, NULL,\n\t      0);\n  left = mkastunary(A_DEREF, m->type, m->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse a parenthesised expression and\n// return an AST node representing it.\nstatic struct ASTnode *paren_expression(int ptp) {\n  struct ASTnode *n;\n  int type = 0;\n  struct symtable *ctype = NULL;\n\n  // Beginning of a parenthesised expression, skip the '('.\n  scan(&Token);\n\n  // If the token after is a type identifier, this is a cast expression\n  switch (Token.token) {\n  case T_IDENT:\n    // We have to see if the identifier matches a typedef.\n    // If not, treat it as an expression.\n    if (findtypedef(Text) == NULL) {\n      n = binexpr(0);\t// ptp is zero as expression inside ( )\n      break;\n    }\n  case T_VOID:\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n  case T_STRUCT:\n  case T_UNION:\n  case T_ENUM:\n    // Get the type inside the parentheses\n    type = parse_cast(&ctype);\n\n    // Skip the closing ')' and then parse the following expression\n    rparen();\n\n  default:\n    n = binexpr(ptp);\t\t// Scan in the expression. We pass in ptp\n\t\t\t\t// as the cast doesn't change the\n\t\t\t\t// expression's precedence\n  }\n\n  // We now have at least an expression in n, and possibly a non-zero type\n  // in type if there was a cast. Skip the closing ')' if there was no cast.\n  if (type == 0)\n    rparen();\n  else\n    // Otherwise, make a unary AST node for the cast\n    n = mkastunary(A_CAST, type, ctype, n, NULL, 0);\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(int ptp) {\n  struct ASTnode *n;\n  struct symtable *enumptr;\n  struct symtable *varptr;\n  int id;\n  int type = 0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type = parse_stars(parse_type(&ctype, &class));\n\n    // Get the type's size\n    size = typesize(type, ctype);\n    rparen();\n\n    // Make a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    id = genglobstr(Text, 0);\n\n    // For successive STRLIT tokens, append their contents\n    // to this one\n    while (1) {\n      scan(&Peektoken);\n      if (Peektoken.token != T_STRLIT) break;\n      genglobstr(Text, 1);\n      scan(&Token);\t// To skip it properly\n    }\n\n    // Now make a leaf AST node for it. id is the string's label.\n    genglobstrend();\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, NULL, id);\n    break;\n\n  case T_IDENT:\n    // If the identifier matches an enum value,\n    // return an A_INTLIT node\n    if ((enumptr = findenumval(Text)) != NULL) {\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, enumptr->st_posn);\n      break;\n    }\n    // See if this identifier exists as a symbol. For arrays, set rvalue to 1.\n    if ((varptr = findsymbol(Text)) == NULL)\n      fatals(\"Unknown variable or function\", Text);\n    switch (varptr->stype) {\n    case S_VARIABLE:\n      n = mkastleaf(A_IDENT, varptr->type, varptr->ctype, varptr, 0);\n      break;\n    case S_ARRAY:\n      n = mkastleaf(A_ADDR, varptr->type, varptr->ctype, varptr, 0);\n      n->rvalue = 1;\n      break;\n    case S_FUNCTION:\n      // Function call, see if the next token is a left parenthesis\n      scan(&Token);\n      if (Token.token != T_LPAREN)\n\tfatals(\"Function name used without parentheses\", Text);\n      return (funccall());\n    default:\n      fatals(\"Identifier not a scalar or array variable\", Text);\n    }\n    break;\n\n  case T_LPAREN:\n    return (paren_expression(ptp));\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(int ptp) {\n  struct ASTnode *n;\n\n  // Get the primary expression\n  n = primary(ptp);\n\n  // Loop until there are no more postfix operators\n  while (1) {\n    switch (Token.token) {\n    case T_LBRACKET:\n      // An array reference\n      n = array_access(n);\n      break;\n\n    case T_DOT:\n      // Access into a struct or union\n      n = member_access(n, 0);\n      break;\n\n    case T_ARROW:\n      // Pointer access into a struct or union\n      n = member_access(n, 1);\n      break;\n\n    case T_INC:\n      // Post-increment: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot ++ on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTINC;\n      break;\n\n    case T_DEC:\n      // Post-decrement: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot -- on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTDEC;\n      break;\n\n    default:\n      return (n);\n    }\n  }\n\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_MOD)\n    return (tokentype);\n  fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10,\t\t\t// T_ASMINUS, T_ASSTAR,\n  10, 10,\t\t\t// T_ASSLASH, T_ASMOD,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110, 110\t\t\t// T_STAR, T_SLASH, T_MOD\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_MOD)\n    fatals(\"Token with no precedence in op_precedence:\", Tstring[tokentype]);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (prec);\n}\n\n// prefix_expression: postfix_expression\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstatic struct ASTnode *prefix(int ptp) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Prevent '&' being performed on an array\n    if (tree->sym->stype == S_ARRAY)\n      fatal(\"& operator cannot be performed on an array\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression.\n    // Make it an rvalue\n    scan(&Token);\n    tree = prefix(ptp);\n    tree->rvalue= 1;\n\n    // Ensure the tree's type is a pointer\n    if (!ptrtype(tree->type))\n      fatal(\"* operator must be followed by an expression of pointer type\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree =\n      mkastunary(A_DEREF, value_at(tree->type), tree->ctype, tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this if needed to int so that it's signed\n    tree->rvalue = 1;\n    if (tree->type == P_CHAR)\n      tree->type = P_INT;\n    tree = mkastunary(A_NEGATE, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  default:\n    tree = postfix(ptp);\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix(ptp);\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp = binexpr(0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. XXX We should also\n      // consider the third expression's type.\n      return (mkastnode\n\t      (A_TERNARY, right->type, right->ctype, left, right, ltemp,\n\t       NULL, 0));\n\n    case A_ASSIGN:\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, left->ctype, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n      break;\n\n    default:\n      // We are not doing a ternary or assignment, so both trees should\n      // be rvalues. Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, right->ctype, ASTop);\n      rtemp = modify_type(right, left->type, left->ctype, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left->ctype, left, NULL,\n\t\tright, NULL, 0);\n\n    // Some operators produce an int result regardless of their operands\n    switch (binastop(tokentype)) {\n    case A_LOGOR:\n    case A_LOGAND:\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      left->type = P_INT;\n    }\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "60_TripleTest/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\nstatic void update_line(struct ASTnode *n) {\n  // Output the line into the assembly if we've\n  // changed the line number in the AST node\n  if (n->linenum != 0 && Line != n->linenum) {\n    Line = n->linenum;\n    cglinenum(Line);\n  }\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs(reg);\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    if (c->left)\n      genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs(NOREG);\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for an\n// A_LOGAND or A_LOGOR operation\nstatic int gen_logandor(struct ASTnode *n) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n  int reg;\n\n  // Generate the code for the left expression\n  // followed by the jump to the false label\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(NOREG);\n\n  // Generate the code for the right expression\n  // followed by the jump to the false label\n  reg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(reg);\n\n  // We didn't jump so set the right boolean value\n  if (n->op == A_LOGAND) {\n    cgloadboolean(reg, 1);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 0);\n  } else {\n    cgloadboolean(reg, 0);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 1);\n  }\n  cglabel(Lend);\n  return (reg);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // Save the registers before we copy the arguments\n  spill_all_regs();\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  // genfreeregs(NOREG);\n\n  // Get a register to hold the result of the two expressions\n  reg = alloc_register();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  cgfreereg(expreg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  cgfreereg(expreg);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg = NOREG, rightreg = NOREG;\n\n  // Empty tree, do nothing\n  if (n == NULL)\n    return (NOREG);\n\n  // Update the line number in the output\n  update_line(n);\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n  case A_IF:\n    return (genIF(n, looptoplabel, loopendlabel));\n  case A_WHILE:\n    return (genWHILE(n));\n  case A_SWITCH:\n    return (genSWITCH(n));\n  case A_FUNCCALL:\n    return (gen_funccall(n));\n  case A_TERNARY:\n    return (gen_ternary(n));\n  case A_LOGOR:\n    return (gen_logandor(n));\n  case A_LOGAND:\n    return (gen_logandor(n));\n  case A_GLUE:\n    // Do each child statement, and free the\n    // registers after each child\n    if (n->left != NULL)\n      genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    if (n->right != NULL)\n      genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    return (NOREG);\n  case A_FUNCTION:\n    // Generate the function's preamble before the code\n    // in the child sub-tree\n    cgfuncpreamble(n->sym);\n    genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n    cgfuncpostamble(n->sym);\n    return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n  case A_ADD:\n    return (cgadd(leftreg, rightreg));\n  case A_SUBTRACT:\n    return (cgsub(leftreg, rightreg));\n  case A_MULTIPLY:\n    return (cgmul(leftreg, rightreg));\n  case A_DIVIDE:\n    return (cgdivmod(leftreg, rightreg, A_DIVIDE));\n  case A_MOD:\n    return (cgdivmod(leftreg, rightreg, A_MOD));\n  case A_AND:\n    return (cgand(leftreg, rightreg));\n  case A_OR:\n    return (cgor(leftreg, rightreg));\n  case A_XOR:\n    return (cgxor(leftreg, rightreg));\n  case A_LSHIFT:\n    return (cgshl(leftreg, rightreg));\n  case A_RSHIFT:\n    return (cgshr(leftreg, rightreg));\n  case A_EQ:\n  case A_NE:\n  case A_LT:\n  case A_GT:\n  case A_LE:\n  case A_GE:\n    // If the parent AST node is an A_IF, A_WHILE or A_TERNARY,\n    // generate a compare followed by a jump. Otherwise, compare\n    // registers and set one to 1 or 0 based on the comparison.\n    if (parentASTop == A_IF || parentASTop == A_WHILE ||\n\tparentASTop == A_TERNARY)\n      return (cgcompare_and_jump\n\t      (n->op, leftreg, rightreg, iflabel, n->left->type));\n    else\n      return (cgcompare_and_set(n->op, leftreg, rightreg, n->left->type));\n  case A_INTLIT:\n    return (cgloadint(n->a_intvalue, n->type));\n  case A_STRLIT:\n    return (cgloadglobstr(n->a_intvalue));\n  case A_IDENT:\n    // Load our value if we are an rvalue\n    // or we are being dereferenced\n    if (n->rvalue || parentASTop == A_DEREF) {\n      return (cgloadvar(n->sym, n->op));\n    } else\n      return (NOREG);\n  case A_ASPLUS:\n  case A_ASMINUS:\n  case A_ASSTAR:\n  case A_ASSLASH:\n  case A_ASMOD:\n  case A_ASSIGN:\n\n    // For the '+=' and friends operators, generate suitable code\n    // and get the register with the result. Then take the left child,\n    // make it the right child so that we can fall into the assignment code.\n    switch (n->op) {\n    case A_ASPLUS:\n      leftreg = cgadd(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASMINUS:\n      leftreg = cgsub(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASSTAR:\n      leftreg = cgmul(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASSLASH:\n      leftreg = cgdivmod(leftreg, rightreg, A_DIVIDE);\n      n->right = n->left;\n      break;\n    case A_ASMOD:\n      leftreg = cgdivmod(leftreg, rightreg, A_MOD);\n      n->right = n->left;\n      break;\n    }\n\n    // Now into the assignment code\n    // Are we assigning to an identifier or through a pointer?\n    switch (n->right->op) {\n    case A_IDENT:\n      if (n->right->sym->class == C_GLOBAL ||\n\t  n->right->sym->class == C_EXTERN ||\n\t  n->right->sym->class == C_STATIC)\n\treturn (cgstorglob(leftreg, n->right->sym));\n      else\n\treturn (cgstorlocal(leftreg, n->right->sym));\n    case A_DEREF:\n      return (cgstorderef(leftreg, rightreg, n->right->type));\n    default:\n      fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n    }\n  case A_WIDEN:\n    // Widen the child's type to the parent's type\n    return (cgwiden(leftreg, n->left->type, n->type));\n  case A_RETURN:\n    cgreturn(leftreg, Functionid);\n    return (NOREG);\n  case A_ADDR:\n    return (cgaddress(n->sym));\n  case A_DEREF:\n    // If we are an rvalue, dereference to get the value we point at,\n    // otherwise leave it for A_ASSIGN to store through the pointer\n    if (n->rvalue)\n      return (cgderef(leftreg, n->left->type));\n    else\n      return (leftreg);\n  case A_SCALE:\n    // Small optimisation: use shift if the\n    // scale value is a known power of two\n    switch (n->a_size) {\n    case 2:\n      return (cgshlconst(leftreg, 1));\n    case 4:\n      return (cgshlconst(leftreg, 2));\n    case 8:\n      return (cgshlconst(leftreg, 3));\n    default:\n      // Load a register with the size and\n      // multiply the leftreg by this size\n      rightreg = cgloadint(n->a_size, P_INT);\n      return (cgmul(leftreg, rightreg));\n    }\n  case A_POSTINC:\n  case A_POSTDEC:\n    // Load and decrement the variable's value into a register\n    // and post increment/decrement it\n    return (cgloadvar(n->sym, n->op));\n  case A_PREINC:\n  case A_PREDEC:\n    // Load and decrement the variable's value into a register\n    // and pre increment/decrement it\n    return (cgloadvar(n->left->sym, n->op));\n  case A_NEGATE:\n    return (cgnegate(leftreg));\n  case A_INVERT:\n    return (cginvert(leftreg));\n  case A_LOGNOT:\n    return (cglognot(leftreg));\n  case A_TOBOOL:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, set the register\n    // to 0 or 1 based on it's zeroeness or non-zeroeness\n    return (cgboolean(leftreg, parentASTop, iflabel));\n  case A_BREAK:\n    cgjump(loopendlabel);\n    return (NOREG);\n  case A_CONTINUE:\n    cgjump(looptoplabel);\n    return (NOREG);\n  case A_CAST:\n    return (leftreg);\t\t// Not much to do\n  default:\n    fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble(char *filename) {\n  cgpreamble(filename);\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs(int keepreg) {\n  freeall_registers(keepreg);\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\n\n// Generate a global string.\n// If append is true, append to\n// previous genglobstr() call.\nint genglobstr(char *strvalue, int append) {\n  int l = genlabel();\n  cgglobstr(l, strvalue, append);\n  return (l);\n}\nvoid genglobstrend(void) {\n  cgglobstrend();\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "60_TripleTest/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\nint toupper(int c);\nint tolower(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "60_TripleTest/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n\nint * __errno_location(void);\n\n#define errno (* __errno_location())\n\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "60_TripleTest/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "60_TripleTest/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "60_TripleTest/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n#ifndef EOF\n# define EOF (-1)\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint sprintf(char *str, char *format);\nint snprintf(char *str, size_t size, char *format);\nint fgetc(FILE *stream);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\nFILE *popen(char *command, char *type);\nint pclose(FILE *stream);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "60_TripleTest/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\nint system(char *command);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "60_TripleTest/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\nint strcmp(char *s1, char *s2);\nint strncmp(char *s1, char *s2, size_t n);\nchar *strerror(int errnum);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "60_TripleTest/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "60_TripleTest/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix;\n  posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Linestart = 1;\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token = 0;\t\t// and set there is no lookahead token\n  genpreamble(filename);\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n\n  // Dump the symbol table if requested\n  if (O_dumpsym) {\n    printf(\"Symbols for %s\\n\", filename);\n    dumpsymtables();\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n#ifdef __NASM__\n  char *incfilename = alter_suffix(filename, 'n');\n  if (incfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  sprintf(cmd, \"%s %s %s\", ASCMD, outfilename, filename);\n#else\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n#endif\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char **objlist) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcSTM] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -M dump the symbol table for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char **argv) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, j, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_dumpsym = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'M':\n\t  O_dumpsym = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "60_TripleTest/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "60_TripleTest/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "60_TripleTest/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  int i;\n  for (i = 0; s[i] != '\\0'; i++)\n    if (s[i] == (char) c)\n      return (i);\n  return (-1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (Linestart && c == '#') {\t// We've hit a pre-processor statement\n    Linestart = 0;\t\t// No longer at the start of the line\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n\n  Linestart = 0;\t\t// No longer at the start of the line\n  if ('\\n' == c) {\n    Line++;\t\t\t// Increment line count\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n  // We hit a non-hex character, put it back\n  putback(c);\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n  return (n);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn (hexchar());\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = (char)c;\n  }\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = (char)c;\n    }\n    c = next();\n  }\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\", \"%=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"%\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case '%':\n      if ((c = next()) == '=') {\n\tt->token = T_ASMOD;\n      } else {\n\tputback(c);\n\tt->token = T_MOD;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "60_TripleTest/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, NULL, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, NULL, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, NULL, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree= NULL;\n\n  // Ensure we have 'return'\n  match(T_RETURN, \"return\");\n\n  // See if we have a return value\n  if (Token.token == T_LPAREN) {\n    // Can't return a value if function returns P_VOID\n    if (Functionid->type == P_VOID)\n      fatal(\"Can't return from a void function\");\n\n    // Skip the left parenthesis\n    lparen();\n\n    // Parse the following expression\n    tree = binexpr(0);\n\n    // Ensure this is compatible with the function's type\n    tree = modify_type(tree, Functionid->type, Functionid->ctype, 0);\n    if (tree == NULL)\n      fatal(\"Incompatible type to return\");\n\n    // Get the ')'\n    rparen();\n  }\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, NULL, tree, NULL, 0);\n\n  // Get the ';'\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, P_NONE, NULL, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, P_NONE, NULL, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *body, *n, *c;\n  struct ASTnode *casetree = NULL, *casetail;\n  int inloop = 1, casecount = 0;\n  int seendefault = 0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left = binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n = mkastunary(A_SWITCH, P_NONE, NULL, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch (Token.token) {\n\t// Leave the loop when we hit a '}'\n      case T_RBRACE:\n\tif (casecount == 0)\n\t  fatal(\"No cases in switch\");\n\tinloop = 0;\n\tbreak;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token == T_DEFAULT) {\n\t  ASTop = A_DEFAULT;\n\t  seendefault = 1;\n\t  scan(&Token);\n\t} else {\n\t  ASTop = A_CASE;\n\t  scan(&Token);\n\t  left = binexpr(0);\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue = left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n\t  // that there isn't a duplicate case value\n\t  for (c = casetree; c != NULL; c = c->right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n\t}\n\n\t// Scan the ':' and increment the casecount\n\tmatch(T_COLON, \":\");\n\tcasecount++;\n\n\t// If the next token is a T_CASE, the existing case will fall\n\t// into the next case. Otherwise, parse the case body.\n\tif (Token.token == T_CASE)\n\t  body = NULL;\n\telse\n\t  body = compound_statement(1);\n\n\t// Build a sub-tree with any compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree == NULL) {\n\t  casetree = casetail =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t} else {\n\t  casetail->right =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t  casetail = casetail->right;\n\t}\n\tbreak;\n      default:\n\tfatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue = casecount;\n  n->right = casetree;\n  rbrace();\n\n  return (n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n  int linenum= Line;\n\n  switch (Token.token) {\n    case T_SEMI:\n      // An empty statement\n      semi();\n      break;\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      stmt->linenum= linenum;\n      rbrace();\n      return (stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt = binexpr(0);\n        stmt->linenum= linenum;\n\tsemi();\n\treturn (stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      stmt= if_statement(); stmt->linenum= linenum; return(stmt);\n    case T_WHILE:\n      stmt= while_statement(); stmt->linenum= linenum; return(stmt);\n    case T_FOR:\n      stmt= for_statement(); stmt->linenum= linenum; return(stmt);\n    case T_RETURN:\n      stmt= return_statement(); stmt->linenum= linenum; return(stmt);\n    case T_BREAK:\n      stmt= break_statement(); stmt->linenum= linenum; return(stmt);\n    case T_CONTINUE:\n      stmt= continue_statement(); stmt->linenum= linenum; return(stmt);\n    case T_SWITCH:\n      stmt= switch_statement(); stmt->linenum= linenum; return(stmt);\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt = binexpr(0);\n      stmt->linenum= linenum;\n      semi();\n      return (stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Leave if we've hit the end token. We do this first to allow\n    // an empty compound statement\n    if (Token.token == T_RBRACE)\n      return (left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT))\n      return (left);\n\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, NULL, left, NULL, tree, NULL, 0);\n    }\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n"
  },
  {
    "path": "60_TripleTest/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n#ifdef __NASM__\n  node->extinit = 0;\n#endif\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list,\n\t\t\t\t      int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class == 0 || class == list->class)\n\treturn (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead = Globtail = NULL;\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Membhead = Membtail = NULL;\n  Structhead = Structtail = NULL;\n  Unionhead = Uniontail = NULL;\n  Enumhead = Enumtail = NULL;\n  Typehead = Typetail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev = NULL;\n\n  // Walk the global table looking for static entries\n  for (g = Globhead; g != NULL; g = g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL)\n\tprev->next = g->next;\n      else\n\tGlobhead->next = g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n\tif (prev != NULL)\n\t  Globtail = prev;\n\telse\n\t  Globtail = Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev = g;\n}\n\n// Dump a single symbol\nstatic void dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n    case P_VOID:\n      printf(\"void \");\n      break;\n    case P_CHAR:\n      printf(\"char \");\n      break;\n    case P_INT:\n      printf(\"int \");\n      break;\n    case P_LONG:\n      printf(\"long \");\n      break;\n    case P_STRUCT:\n      if (sym->ctype != NULL)\n\tprintf(\"struct %s \", sym->ctype->name);\n      else\n\tprintf(\"struct %s \", sym->name);\n      break;\n    case P_UNION:\n      if (sym->ctype != NULL)\n\tprintf(\"union %s \", sym->ctype->name);\n      else\n\tprintf(\"union %s \", sym->name);\n      break;\n    default:\n      printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++)\n    printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      break;\n    case S_FUNCTION:\n      printf(\"()\");\n      break;\n    case S_ARRAY:\n      printf(\"[]\");\n      break;\n    default:\n      printf(\" unknown stype\");\n  }\n\n  switch (sym->class) {\n    case C_GLOBAL:\n      printf(\": global\");\n      break;\n    case C_LOCAL:\n      printf(\": local\");\n      break;\n    case C_PARAM:\n      printf(\": param\");\n      break;\n    case C_EXTERN:\n      printf(\": extern\");\n      break;\n    case C_STATIC:\n      printf(\": static\");\n      break;\n    case C_STRUCT:\n      printf(\": struct\");\n      break;\n    case C_UNION:\n      printf(\": union\");\n      break;\n    case C_MEMBER:\n      printf(\": member\");\n      break;\n    case C_ENUMTYPE:\n      printf(\": enumtype\");\n      break;\n    case C_ENUMVAL:\n      printf(\": enumval\");\n      break;\n    case C_TYPEDEF:\n      printf(\": typedef\");\n      break;\n    default:\n      printf(\": unknown class\");\n  }\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      if (sym->class == C_ENUMVAL)\n\tprintf(\", value %d\\n\", sym->st_posn);\n      else\n\tprintf(\", size %d\\n\", sym->size);\n      break;\n    case S_FUNCTION:\n      printf(\", %d params\\n\", sym->nelems);\n      break;\n    case S_ARRAY:\n      printf(\", %d elems, size %d\\n\", sym->nelems, sym->size);\n      break;\n  }\n\n  switch (sym->type & (~0xf)) {\n    case P_STRUCT:\n    case P_UNION:\n      dumptable(sym->member, NULL, 4);\n  }\n\n  switch (sym->stype) {\n    case S_FUNCTION:\n      dumptable(sym->member, NULL, 4);\n  }\n}\n\n// Dump one symbol table\nvoid dumptable(struct symtable *head, char *name, int indent) {\n  struct symtable *sym;\n\n  if (head != NULL && name != NULL)\n    printf(\"%s\\n--------\\n\", name);\n  for (sym = head; sym != NULL; sym = sym->next)\n    dumpsym(sym, indent);\n}\n\nvoid dumpsymtables(void) {\n  dumptable(Globhead, \"Global\", 0);\n  printf(\"\\n\");\n  dumptable(Enumhead, \"Enums\", 0);\n  printf(\"\\n\");\n  dumptable(Typehead, \"Typedefs\", 0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input032.c",
    "content": "Unknown variable or function:pizza on line 4 of input032.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input042.c",
    "content": "Unknown variable or function:fred on line 3 of input042.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input043.c",
    "content": "Unknown variable or function:b on line 3 of input043.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input044.c",
    "content": "Unknown variable or function:z on line 3 of input044.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input046.c",
    "content": "* operator must be followed by an expression of pointer type on line 3 of input046.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input059.c",
    "content": "Unknown variable or function:y on line 3 of input059.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input060.c",
    "content": "Expression is not a struct/union on line 3 of input060.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input061.c",
    "content": "Expression is not a pointer to a struct/union on line 3 of input061.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input086.c",
    "content": "Function definition not at global level on line 2 of input086.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input093.c",
    "content": "Unknown variable or function:fred on line 1 of input093.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input124.c",
    "content": "Cannot ++ on rvalue on line 6 of input124.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input126.c",
    "content": "Unknown variable or function:ptr on line 7 of input126.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input129.c",
    "content": "Cannot ++ and/or -- more than once on line 6 of input129.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input141.c",
    "content": "Declaration of array parameters is not implemented on line 4 of input141.c\n"
  },
  {
    "path": "60_TripleTest/tests/err.input142.c",
    "content": "Array must have non-zero elements:fred on line 1 of input142.c\n"
  },
  {
    "path": "60_TripleTest/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "60_TripleTest/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "60_TripleTest/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "60_TripleTest/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "60_TripleTest/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "60_TripleTest/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "60_TripleTest/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "60_TripleTest/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "60_TripleTest/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "60_TripleTest/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "60_TripleTest/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "60_TripleTest/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "60_TripleTest/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "60_TripleTest/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "60_TripleTest/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "60_TripleTest/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "60_TripleTest/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "60_TripleTest/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "60_TripleTest/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "60_TripleTest/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "60_TripleTest/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "60_TripleTest/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "60_TripleTest/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "60_TripleTest/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "60_TripleTest/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "60_TripleTest/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "60_TripleTest/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "60_TripleTest/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "60_TripleTest/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "60_TripleTest/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "60_TripleTest/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input122.c",
    "content": "#include <stdio.h>\n\nint x, y, z1, z2;\n\nint main() {\n  for (x= 0; x <= 1; x++) {\n    for (y= 0; y <= 1; y++) {\n      z1= x || y; z2= x && y;\n      printf(\"x %d, y %d, x || y %d, x && y %d\\n\", x, y, z1, z2);\n    }\n  }\n  \n  //z= x || y;\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input123.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  for (x=0; x < 20; x++)\n    switch(x) {\n      case 2:\n      case 3:\n      case 5:\n      case 7:\n      case 11: printf(\"%2d infant prime\\n\", x); break;\n      case 13:\n      case 17:\n      case 19: printf(\"%2d teen   prime\\n\", x); break;\n      case 0:\n      case 1:\n      case 4:\n      case 6:\n      case 8:\n      case 9:\n      case 10:\n      case 12: printf(\"%2d infant composite\\n\", x); break;\n      default: printf(\"%2d teen   composite\\n\", x); break;\n    }\n\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input124.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary++;\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input125.c",
    "content": "#include <stdio.h>\n\nint ary[5];\nint *ptr;\nint x;\n\nint main() {\n  ary[3]= 2008;\n  ptr= ary;\t\t\t// Load ary's address into ptr\n  x= ary[3]; printf(\"%d\\n\", x);\n  x= ptr[3]; printf(\"%d\\n\", x); // Treat ptr as an array\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input126.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary[3]= 2008;\n  ptr= &ary;\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input127.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nvoid fred(int *ptr) {\t\t// Receive a pointer\n  printf(\"%d\\n\", ptr[3]);\n}\n\nint main() {\n  ary[3]= 2008;\n  printf(\"%d\\n\", ary[3]);\n  fred(ary);\t\t\t// Pass ary as a pointer\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input128.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int val;\n  struct foo *next;\n};\n\nstruct foo head, mid, tail;\n\nint main() {\n  struct foo *ptr;\n  tail.val= 20; tail.next= NULL;\n  mid.val= 15; mid.next= &tail;\n  head.val= 10; head.next= &mid;\n\n  ptr= &head;\n  printf(\"%d %d\\n\", head.val, ptr->val);\n  printf(\"%d %d\\n\", mid.val, ptr->next->val);\n  printf(\"%d %d\\n\", tail.val, ptr->next->next->val);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input129.c",
    "content": "#include <stdio.h>\n\nint x= 6;\n\nint main() {\n  printf(\"%d\\n\", x++ ++);\n  return(0);\n}\n\n"
  },
  {
    "path": "60_TripleTest/tests/input130.c",
    "content": "#include <stdio.h>\n\nchar *x= \"foo\";\n\nint main() {\n  printf(\"Hello \" \"world\" \"\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input131.c",
    "content": "#include <stdio.h>\n\nvoid donothing() { }\n\nint main() {\n  int x=0;\n  printf(\"Doing nothing... \"); donothing();\n  printf(\"nothing done\\n\");\n\n  while (++x < 100) ;\n  printf(\"x is now %d\\n\", x);\n\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input132.c",
    "content": "extern int fred;\nint fred;\n\nint mary;\nextern int mary;\n\nint main() { return(0); }\n"
  },
  {
    "path": "60_TripleTest/tests/input133.c",
    "content": "#include <stdio.h>\n\nextern int fred[];\nint fred[23];\n\nchar mary[100];\nextern char mary[];\n\nvoid main() { printf(\"OK\\n\"); }\n"
  },
  {
    "path": "60_TripleTest/tests/input134.c",
    "content": "#include <stdio.h>\n\nchar y = 'a';\nchar *x;\n\nint main() {\n  x= &y;        if (x && y == 'a') printf(\"1st match\\n\");\n  x= NULL;      if (x && y == 'a') printf(\"2nd match\\n\");\n  x= &y; y='b'; if (x && y == 'a') printf(\"3rd match\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input135.c",
    "content": "#include <stdio.h>\n\nvoid fred() {\n  int x= 5;\n  printf(\"testing x\\n\");\n  if (x > 4) return;\n  printf(\"x below 5\\n\");\n}\n\nint main() {\n  fred();\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input136.c",
    "content": "#include <stdio.h>\n\nint add(int x, int y) {\n  return(x+y);\n}\n\nint main() {\n  int result;\n  result= 3 * add(2,3) - 5 * add(4,6);\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input137.c",
    "content": "#include <stdio.h>\n\nint a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8;\n\nint main() {\n  int x;\n  x= ((((((a + b) + c) + d) + e) + f) + g) + h;\n  x= a + (b + (c + (d + (e + (f + (g + h))))));\n  printf(\"x is %d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input138.c",
    "content": "#include <stdio.h>\n\nint x, y, z;\n\nint a=1;\nint *aptr;\n\nint main() {\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x && y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x || y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // Now some lazy evaluation\n  aptr= NULL;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  aptr= &a;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input139.c",
    "content": "#include <stdio.h>\n\nint same(int x) { return(x); }\n\nint main() {\n  int a= 3;\n\n  if (same(a) && same(a) >= same(a))\n    printf(\"same apparently\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input140.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int  i;\n  int  ary[5];\n  char z;\n\n  // Write below the array\n  z= 'H';\n\n  // Fill the array\n  for (i=0; i < 5; i++)\n    ary[i]= i * i;\n\n  // Write above the array\n  i=14;\n\n  // Print out the array\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", ary[i]);\n\n  // See if either side is OK\n  printf(\"%d %c\\n\", i, z);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input141.c",
    "content": "static int fred[5];\nint jim;\n\nint foo(int mary[6]) { return(5); }\n"
  },
  {
    "path": "60_TripleTest/tests/input142.c",
    "content": "static int fred[];\nint jim;\n"
  },
  {
    "path": "60_TripleTest/tests/input143.c",
    "content": "#include <stdio.h>\n\nchar foo;\nchar *a, *b, *c;\n\nint main() {\n\n  a= b= c= NULL;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  a= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  b= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  c= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  else\n    printf(\"All  three  are non-NULL\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input144.c",
    "content": "#include <stdio.h>\n#include <errno.h>\n#include <string.h>\nchar *filename= \"fred\";\nint main() {\n    fprintf(stdout, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input145.c",
    "content": "#include <stdio.h>\n\nchar *str= \"qwertyuiop\";\n\nint list[]= {3, 5, 7, 9, 11, 13, 15};\n\nint *lptr;\n\nint main() {\n  printf(\"%c\\n\", *str);\n  str= str + 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str -= 1; printf(\"%c\\n\", *str);\n\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input146.c",
    "content": "#include <stdio.h>\n\nchar *str= \"qwertyuiop\";\n\nint list[]= {3, 5, 7, 9, 11, 13, 15};\n\nint *lptr;\n\nint main() {\n  printf(\"%c\\n\", *str);\n  str= str + 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str -= 1; printf(\"%c\\n\", *str);\n  str++; printf(\"%c\\n\", *str);\n  str--; printf(\"%c\\n\", *str);\n  ++str; printf(\"%c\\n\", *str);\n  --str; printf(\"%c\\n\\n\", *str);\n\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  lptr++   ; printf(\"%d\\n\", *lptr);\n  lptr--   ; printf(\"%d\\n\", *lptr);\n  ++lptr   ; printf(\"%d\\n\", *lptr);\n  --lptr   ; printf(\"%d\\n\", *lptr);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input147.c",
    "content": "#include <stdio.h>\n\nint a;\n\nint main() {\n  printf(\"%d\\n\", 24 % 9);\n  printf(\"%d\\n\", 31 % 11);\n  a= 24; a %= 9; printf(\"%d\\n\",a);\n  a= 31; a %= 11; printf(\"%d\\n\",a);\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input148.c",
    "content": "#include <stdio.h>\n\nchar *argv[]= { \"unused\", \"-fish\", \"-cat\", \"owl\" };\nint argc= 4;\n\nint main() {\n  int i;\n\n  for (i = 1; i < argc; i++) {\n    printf(\"i is %d\\n\", i);\n    if (*argv[i] != '-') break;\n  }\n\n  while (i < argc) {\n    printf(\"leftover %s\\n\", argv[i]);\n    i++;\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/input149.c",
    "content": "#include <stdio.h>\n\nstatic int localOffset=0;\n\nstatic int newlocaloffset(int size) {\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\nint main() {\n  int i, r;\n  for (i=1; i <= 12; i++) {\n    r= newlocaloffset(i);\n    printf(\"%d %d\\n\", i, r);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "60_TripleTest/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "60_TripleTest/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "60_TripleTest/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "60_TripleTest/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "60_TripleTest/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "60_TripleTest/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "60_TripleTest/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "60_TripleTest/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "60_TripleTest/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "60_TripleTest/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "60_TripleTest/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "60_TripleTest/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "60_TripleTest/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "60_TripleTest/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "60_TripleTest/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "60_TripleTest/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "60_TripleTest/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "60_TripleTest/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "60_TripleTest/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "60_TripleTest/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "60_TripleTest/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "60_TripleTest/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "60_TripleTest/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "60_TripleTest/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "60_TripleTest/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "60_TripleTest/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "60_TripleTest/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "60_TripleTest/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "60_TripleTest/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "60_TripleTest/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "60_TripleTest/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "60_TripleTest/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "60_TripleTest/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "60_TripleTest/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "60_TripleTest/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "60_TripleTest/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "60_TripleTest/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "60_TripleTest/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "60_TripleTest/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "60_TripleTest/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "60_TripleTest/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "60_TripleTest/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "60_TripleTest/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "60_TripleTest/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "60_TripleTest/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "60_TripleTest/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "60_TripleTest/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "60_TripleTest/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "60_TripleTest/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "60_TripleTest/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "60_TripleTest/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "60_TripleTest/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "60_TripleTest/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "60_TripleTest/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "60_TripleTest/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "60_TripleTest/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "60_TripleTest/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "60_TripleTest/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "60_TripleTest/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "60_TripleTest/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "60_TripleTest/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "60_TripleTest/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "60_TripleTest/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "60_TripleTest/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "60_TripleTest/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "60_TripleTest/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "60_TripleTest/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "60_TripleTest/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "60_TripleTest/tests/out.input122.c",
    "content": "x 0, y 0, x || y 0, x && y 0\nx 0, y 1, x || y 1, x && y 0\nx 1, y 0, x || y 1, x && y 0\nx 1, y 1, x || y 1, x && y 1\n"
  },
  {
    "path": "60_TripleTest/tests/out.input123.c",
    "content": " 0 infant composite\n 1 infant composite\n 2 infant prime\n 3 infant prime\n 4 infant composite\n 5 infant prime\n 6 infant composite\n 7 infant prime\n 8 infant composite\n 9 infant composite\n10 infant composite\n11 infant prime\n12 infant composite\n13 teen   prime\n14 teen   composite\n15 teen   composite\n16 teen   composite\n17 teen   prime\n18 teen   composite\n19 teen   prime\n"
  },
  {
    "path": "60_TripleTest/tests/out.input125.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "60_TripleTest/tests/out.input127.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "60_TripleTest/tests/out.input128.c",
    "content": "10 10\n15 15\n20 20\n"
  },
  {
    "path": "60_TripleTest/tests/out.input130.c",
    "content": "Hello world\n"
  },
  {
    "path": "60_TripleTest/tests/out.input131.c",
    "content": "Doing nothing... nothing done\nx is now 100\n"
  },
  {
    "path": "60_TripleTest/tests/out.input132.c",
    "content": ""
  },
  {
    "path": "60_TripleTest/tests/out.input133.c",
    "content": "OK\n"
  },
  {
    "path": "60_TripleTest/tests/out.input134.c",
    "content": "1st match\n"
  },
  {
    "path": "60_TripleTest/tests/out.input135.c",
    "content": "testing x\n"
  },
  {
    "path": "60_TripleTest/tests/out.input136.c",
    "content": "-35\n"
  },
  {
    "path": "60_TripleTest/tests/out.input137.c",
    "content": "x is 36\n"
  },
  {
    "path": "60_TripleTest/tests/out.input138.c",
    "content": "0 0 | 0\n0 1 | 0\n1 0 | 0\n1 1 | 1\n0 0 | 0\n0 1 | 1\n1 0 | 1\n1 1 | 1\naptr is NULL or doesn't point at 1\naptr points at 1\n"
  },
  {
    "path": "60_TripleTest/tests/out.input139.c",
    "content": "same apparently\n"
  },
  {
    "path": "60_TripleTest/tests/out.input140.c",
    "content": "0\n1\n4\n9\n16\n5 H\n"
  },
  {
    "path": "60_TripleTest/tests/out.input143.c",
    "content": "One of the three is NULL\nOne of the three is NULL\nOne of the three is NULL\nAll  three  are non-NULL\n"
  },
  {
    "path": "60_TripleTest/tests/out.input144.c",
    "content": "Unable to open fred: Success\n"
  },
  {
    "path": "60_TripleTest/tests/out.input145.c",
    "content": "q\nw\ne\nr\ne\n3\n5\n7\n9\n7\n"
  },
  {
    "path": "60_TripleTest/tests/out.input146.c",
    "content": "q\nw\ne\nr\ne\nr\ne\nr\ne\n\n3\n5\n7\n9\n7\n9\n7\n9\n7\n"
  },
  {
    "path": "60_TripleTest/tests/out.input147.c",
    "content": "6\n9\n6\n9\n"
  },
  {
    "path": "60_TripleTest/tests/out.input148.c",
    "content": "i is 1\ni is 2\ni is 3\nleftover owl\n"
  },
  {
    "path": "60_TripleTest/tests/out.input149.c",
    "content": "1 -4\n2 -8\n3 -12\n4 -16\n5 -21\n6 -27\n7 -34\n8 -42\n9 -51\n10 -61\n11 -72\n12 -84\n"
  },
  {
    "path": "60_TripleTest/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "60_TripleTest/tests/runtests0",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj0 ]\nthen (cd ..; make install; make cwj0)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj0 -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj0 $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "60_TripleTest/tests/runtests0n",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install; make compn0)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo \n   bn=$(echo $i | cut -d. -f1)\n   if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn0 -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn0 $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s ${bn}.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "60_TripleTest/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo \n   bn=$(echo $i | cut -d. -f1)\n   if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s ${bn}.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "60_TripleTest/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->ctype = ctype;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  n->linenum= 0;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n  int i;\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    case A_TOBOOL:\n      fprintf(stdout, \"A_TOBOOL\\n\");\n      return;\n    case A_LOGOR:\n      fprintf(stdout, \"A_LOGOR\\n\");\n      return;\n    case A_LOGAND:\n      fprintf(stdout, \"A_LOGAND\\n\");\n      return;\n    case A_AND:\n      fprintf(stdout, \"A_AND\\n\");\n      return;\n    case A_ASMOD:\n      fprintf(stdout, \"A_ASMOD\\n\");\n      return;\n    case A_INVERT:\n      fprintf(stdout, \"A_INVERT\\n\");\n      return;\n    case A_LOGNOT:\n      fprintf(stdout, \"A_LOGNOT\\n\");\n      return;\n    case A_LSHIFT:\n      fprintf(stdout, \"A_LSHIFT\\n\");\n      return;\n    case A_MOD:\n      fprintf(stdout, \"A_MOD\\n\");\n      return;\n    case A_OR:\n      fprintf(stdout, \"A_OR\\n\");\n      return;\n    case A_RSHIFT:\n      fprintf(stdout, \"A_RSHIFT\\n\");\n      return;\n    case A_TERNARY:\n      fprintf(stdout, \"A_TERNARY\\n\");\n      return;\n    case A_XOR:\n      fprintf(stdout, \"A_XOR\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "60_TripleTest/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n\t\t\t    struct symtable *rctype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // For A_LOGOR and A_LOGAND, both types have to be int or pointer types\n  if (op==A_LOGOR || op==A_LOGAND) {\n    if (!inttype(ltype) && !ptrtype(ltype))\n      return(NULL);\n    if (!inttype(ltype) && !ptrtype(rtype))\n      return(NULL);\n    return (tree);\n  }\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // Tree's size is too big\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, NULL, tree, NULL, 0));\n  }\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return (tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n  // We can scale only on add and subtract operations\n  if (op == A_ADD || op == A_SUBTRACT ||\n      op == A_ASPLUS || op == A_ASMINUS) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, rctype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "61_What_Next/Readme.md",
    "content": "# Part 61: What's Next?\n\nWe've achieved the goal of writing a self-compiling\ncompiler. Now that this goal has been reached, what\nelse could we do with the codebase?\n\nFrom the start, I'm going to say that there are already\na number of working, production-ready C compilers:\n[GCC](https://gcc.gnu.org), [LLVM](https://llvm.org)\netc. We don't need another production-ready C compiler.\nBut the point of writing this compiler was pedagogical:\nto explain the basics of how compilers work, and to\nput this knowledge into practice.\n\nSo, I see the future work on the compiler to continue\nto explain how compilers work and to put this into\npractice.\n\nWith this direction set, let's look at the possibilities.\n\n## Code Cleanup\n\nI wrote the compiler fairly quickly, with only a little\nthought about the overarching design of the code. I think\nthe design is reasonable, but the whole codebase needs\na clean up. There's a fair bit of\n[DRY code](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)\nin places which could be refactored. Some of the code is\nugly and could be improved. Also, some of the comments no\nlonger reflect the code. This wouldn't change the compiler's\nfunctionality, but it would make it easier to understand.\n\n## Fix the Bugs\n\nThe compiler, as it stands, purports to implement a\nspecific subset of the C language. But I'm sure there\nare plenty of bugs in this implementation. We could\nspend some time identifying these bugs and fixing them,\nwhile keeping the compiler's functionality constant.\n\n## Write Out the Final BNF Grammar\n\nThis suggestions goes along with the previous one.\nWe should document the exact subset of the C language\nthat the compiler supports, as a BNF grammar. I did\nwrite snippets of BNF grammar thoughout the journey,\nbut near the end I stopped doing it. It would be \ngood to write out the full, final, BNF grammar.\n\n## Support Variadic Functions\n\nThe compiler still doesn't check that the number of\narguments to a function matches the number of\nfunction parameters. We need this because the compiler\nalso doesn't support variadic functions like `printf()`\nand friends.\n\nSo, we need to add in the `...` token, somehow mark\na function has having either \"exactly N\" or \"N or more\"\nparameters, and then write the code to use this information.\n\n## Add `short`s\n\nIt shouldn't be too hard to add a 16-bit signed `short` type. But Nils\nmentions, in his SubC book, that adding `unsigned` integer to a C\ncompiler is tricky.\n\n## Rewrite the Register Allocation and Spilling\n\nRight now, the mechanism for register allocation and\nregister spilling is really awful, especially the\nspilling of registers before and after a function call.\nThe assembly code is terribly inefficient. I'd like\nto see this rewritten using some of the theory on\nregister allocation, e.g\n[graph colouring](https://en.wikipedia.org/wiki/Register_allocation#Graph-coloring_allocation).\nEven better, if this was written up like the past\njourney steps, it would help newcomers (like me)\nunderstand it better.\n\n## AST Optimisations\n\nI did mention the idea of optimising the generated code\nby restructing the AST trees. An example of this is\n[strength reduction](https://en.wikipedia.org/wiki/Strength_reduction).\nThe [SubC](http://www.t3x.org/subc/) compiler does this,\nand it would be easy to add to our compiler, along with\na writeup. There might be other AST tree optimisations\nthat could be done.\n\n## Code Generation Optimisation\n\nAnother place to do output optimisation is in the code\ngenerator. A good example is\n[peephole optimisation](https://en.wikipedia.org/wiki/Peephole_optimization).\nTo do this, however, the way the assembly code is generated\nwould have to change. Instead of `fprintf()`ing the output,\nit should be stored in a data structure to make it easier for\nthe peephole optimiser to traverse the assembly code. That's\nas far as I've thought, but it would be interesting to do.\n\n## Add Debugging Output\n\nI started to do this in step 59. We should be able to output\n`gdb` directives into the assembly output to allow `gdb` to\nsee the original C source lines, and step through a program\nline by line. Right now, the compiler is outputting this\ninformation but the `gdb` directives are not placed correctly\nin the assembly output. There's another step in here with a\nwriteup on how to do this properly.\n\n## Complete the ARM Backend, plus Others\n\nI did start the ARM back-end, and at the time I promised that\nI would keep it in sync with the x86-64 back-end. Well, I\nbroke that promise as I got too interested in extending the\ncompiler's functionality. Now that the compiler's functionality\nis relatively stable, I should go back and complete the ARM\nback-end. Even better would be a third back-end to prove that\nthe compiler is fairly portable.\n\n## Extending the Recognised Grammar\n\nI've left this suggestion to near the end as it doesn't\ncontinue the theme of explaining how compilers work. There is\nalways scope to add more elements of the C language to the\ncompiler. We don't need to do this to make the compiler\nself-compiling, but it would make the compiler more useful\nas a general-purpose compiler.\n\n## Work Out How to Call `ld` Directly\n\nA long time ago, when I was playing around with BSD and Linux\nsystems, I used to be able to link excecutables by hand with\nthe `ld` command. I've been unable to work out how to do this\non current Linux systems, and I'm relying on `cc` to do the\nlinking for me. I'd love to learn how to link by hand with `ld`\non Linux.\n\n## Port the Compiler to non-Linux Systems\n\nFollowing on from the last point, it would be good to \"port\"\nthe compiler to non-Linux systems like some of the BSD platforms.\n\n## Conclusion\n\nThese are all the possible things that I can of (at the moment)\nto continue the work on our compiler. I will get on to some of\nthem, but at this point I'd be very happy to have other people\nhelp out with the project, and/or fork the compiler's code and\ndo their own thing with it! [Next step](../62_Cleanup/Readme.md)\n"
  },
  {
    "path": "62_Cleanup/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h incdir.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nSRCN= cgn.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\nARMSRCS= cg_arm.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\techo \"#define INCDIR \\\"$(INCDIR)\\\"\" > incdir.h\n\tcc -o cwj -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCS)\n\ncompn: $(SRCN) $(HSRCS)\n\techo \"#define __NASM__ 1\" >> incdir.h\n\tcc -D__NASM__ -o compn -g -Wall -DINCDIR=\\\"$(INCDIR)\\\" $(SRCN)\n\ncwjarm: $(ARMSRCS) $(HSRCS)\n\techo \"#define INCDIR \\\"$(INCDIR)\\\"\" > incdir.h\n\tcc -o cwjarm -g -Wall $(ARMSRCS)\n\tcp cwjarm cwj\n\nincdir.h:\n\techo \"#define INCDIR \\\"$(INCDIR)\\\"\" > incdir.h\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\ninstalln: compn\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp compn $(BINDIR)\n\tchmod +x $(BINDIR)/compn\n\nclean:\n\trm -f cwj cwj[0-9] cwjarm compn compn[0-9] *.o *.s out a.out incdir.h\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\n# Run the tests with the\n# compiler that compiled itself\ntest0: install tests/runtests0 cwj0\n\t(cd tests; chmod +x runtests0; ./runtests0)\n\n# Run the tests with the\n# compiler that compiled itself\ntest0n: install tests/runtests0n compn0\n\t(cd tests; chmod +x runtests0n; ./runtests0n)\n\narmtest: cwjarm tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\ntestn: installn tests/runtestsn\n\t(cd tests; chmod +x runtestsn; ./runtestsn)\n\n# Try to do the triple test\ntriple: cwj1\n\tsize cwj[01]\n\n# Paranoid: quadruple test\nquad: cwj2\n\tsize cwj[012]\n\ncwj2: cwj1 $(SRCS) $(HSRCS)\n\t./cwj1 -o cwj2 $(SRCS)\n\ncwj1: cwj0 $(SRCS) $(HSRCS)\n\t./cwj0 -o cwj1 $(SRCS)\n\ncwj0: install $(SRCS) $(HSRCS)\n\t./cwj  -o cwj0 $(SRCS)\n\n# Try to do the triple test with nasm\ntriplen: compn1\n\tsize compn[01]\n\nquadn: compn2\n\tsize compn[012]\n\ncompn2: compn1 $(SRCN) $(HSRCS)\n\t./compn1 -o compn2 $(SRCN)\n\ncompn1: compn0 $(SRCN) $(HSRCS)\n\t./compn0 -o compn1 $(SRCN)\n\ncompn0: installn $(SRCN) $(HSRCS)\n\techo \"#define __NASM__ 1\" >> incdir.h\n\t./compn  -o compn0 $(SRCN)\n"
  },
  {
    "path": "62_Cleanup/Readme.md",
    "content": "# Part 62: Code Cleanup\n\nThis version of the compiler is essentially the same as in part 60.\nI am using this part to fix up comments, fix up bugs, do a bit of\ncode cleanup, rename some functions and variables etc.\n\n## Some Small Bugfixes\n\nFor the changes to the compiler that I'm planning, I need to be able\nto put structs into structs. Therefore, I should be able to do:\n\n```c\n   printf(\"%d\\n\", thing.member1.age_in_years);\n```\n\nwhere `thing` is a struct, but it has a `member1` which is of type struct.\nTo do this, we need to find the offset of `member1` from the base of\n`thing`, then find the offset of `age_in_years` from the previous offset.\n\nHowever, the code to do this expects the things on the left-hand side of\nthe '.' token to be a variable which has a symbol table entry and thus\na fixed location in memory. We need to fix this to deal with the situation\nwhere the left-hand side of the '.' token is an offset that has already\nbeen calculated.\n\nFortunately, this was quite easy to do. We don't have to change the\nparser code, but let's look at what is  already there. In `member_access()`\nin `expr.c`:\n\n```c\n  // Check that the left AST tree is a struct or union.\n  // If so, change it from an A_IDENT to an A_ADDR so that\n  // we get the base address, not the value at this address.\n  if (!withpointer) {\n    if (left->type == P_STRUCT || left->type == P_UNION)\n      left->op = A_ADDR;\n```\n\nWe mark the left-hand AST tree as A_ADDR (instead of A_IDENT) to say\nthat we need the base address of it, not the value at this address.\n\nNow we need to fix the code generation. When we get an A_ADDR AST node,\nwe either have a variable whose address we need (e.g. `thing` in\n`thing.member1`), or our child tree has the pre-calculated offset\n(e.g. the offset of `member1` in `member1.age_in_years). So in `genAST()`\nin `gen.c`, we do:\n\n```c\n  case A_ADDR:\n    // If we have a symbol, get its address. Otherwise,\n    // the left register already has the address because\n    // it's a member access\n    if (n->sym != NULL)\n      return (cgaddress(n->sym));\n    else\n      return (leftreg);\n```\n\nThat should be all, but we have one more fix. The code to work out the\nalignment of types doesn't deal with structs inside structs, only\nscalar types inside structs. So, I've modified `cgalign()` in `cg.c`\nas follows:\n\n```c\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n  case P_CHAR:\n    break;\n  default:\n    // Align whatever we have now on a 4-byte alignment.\n    // I put the generic code here so it can be reused elsewhere.\n    alignment = 4;\n    offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  }\n  return (offset);\n}\n```\n\nEverything but P_CHAR gets aligned on a 4-byte alignment,\nincluding structs and unions.\n\n## Known but Unfixed Bugs\n\nNow that this Github repository is up and has gained some attention,\nseveral people have reported bugs and misfeatures.\nThe list of open and closed issues is here:\n![https://github.com/DoctorWkt/acwj/issues](https://github.com/DoctorWkt/acwj/issues). If you spot any bugs or misfeatures, feel free to report them.\nHowever, I can't promise I'll get time to fix them all!\n\n## What's Next\n\nI've been reading up on register allocation, and I think I'll add\na linear scan register allocation mechanism to the compiler. To do\nthis, though, I need to add an intermediate representation stage.\nThis will be the goal for the next few stages, but so far I haven't\ndone anything concrete. [Next step](../63_QBE/Readme.md)\n"
  },
  {
    "path": "62_Cleanup/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\n// Switch to the text segment\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\n// Switch to the data segment\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n  case P_CHAR:\n    return (1);\n  case P_INT:\n    return (4);\n  case P_LONG:\n    return (8);\n  default:\n    fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n  case P_CHAR:\n    break;\n  default:\n    // Align whatever we have now on a 4-byte alignment.\n    // I put the generic code here so it can be reused elsewhere.\n    alignment = 4;\n    offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  }\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\n\n// Position of stack pointer offset relative to stack base pointer.\n// We need this to ensure it is aligned on a 16-byte boundary.\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too.\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n  { \"%r10\", \"%r11\", \"%r12\", \"%r13\", \"%r9\", \"%r8\", \"%rcx\", \"%rdx\", \"%rsi\",\n  \"%rdi\"\n};\n\n// We also need the 8-bit and 32-bit register names\nstatic char *breglist[] =\n  { \"%r10b\", \"%r11b\", \"%r12b\", \"%r13b\", \"%r9b\", \"%r8b\", \"%cl\", \"%dl\", \"%sil\",\n  \"%dil\"\n};\n\nstatic char *dreglist[] =\n  { \"%r10d\", \"%r11d\", \"%r12d\", \"%r13d\", \"%r9d\", \"%r8d\", \"%ecx\", \"%edx\",\n  \"%esi\", \"%edi\"\n};\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpopq\\t%s\\n\", reglist[r]);\n}\n\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\nvoid cgfreeallregs(int keepreg) {\n  int i;\n  // fprintf(Outfile, \"# freeing all registers\\n\");\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg = 0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint cgallocreg(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      // fprintf(Outfile, \"# allocated register %s\\n\", reglist[reg]);\n      return (reg);\n    }\n  }\n\n  // We have no registers, so we must spill one\n  reg = (spillreg % NUMFREEREGS);\n  spillreg++;\n  // fprintf(Outfile, \"# spilling reg %s\\n\", reglist[reg]);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nvoid cgfreereg(int reg) {\n  if (freereg[reg] != 0) {\n    // fprintf(Outfile, \"# error trying to free register %s\\n\", reglist[reg]);\n    fatald(\"Error trying to free register\", reg);\n  }\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg = (spillreg % NUMFREEREGS);\n    // fprintf(Outfile, \"# unspilling reg %s\\n\", reglist[reg]);\n    popreg(reg);\n  } else {\n    // fprintf(Outfile, \"# freeing reg %s\\n\", reglist[reg]);\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid cgspillregs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void cgunspillregs(void) {\n  int i;\n\n  for (i = NUMFREEREGS - 1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\n// for one output file\nvoid cgpreamble(char *filename) {\n  cgfreeallregs(NOREG);\n  cgtextseg();\n  fprintf(Outfile, \"\\t.file 1 \");\n  fputc('\"', Outfile);\n  fprintf(Outfile, \"%s\", filename);\n  fputc('\"', Outfile);\n  fputc('\\n', Outfile);\n  fprintf(Outfile,\n\t  \"# internal switch(expr) routine\\n\"\n\t  \"# %%rsi = switch table, %%rax = expr\\n\"\n\t  \"# from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"__switch:\\n\"\n\t  \"        pushq   %%rsi\\n\"\n\t  \"        movq    %%rdx, %%rsi\\n\"\n\t  \"        movq    %%rax, %%rbx\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rcx\\n\"\n\t  \"__next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        movq    %%rax, %%rdx\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmpq    %%rdx, %%rbx\\n\"\n\t  \"        jnz     __no\\n\"\n\t  \"        popq    %%rsi\\n\"\n\t  \"        jmp     *%%rax\\n\"\n\t  \"__no:\\n\"\n\t  \"        loop    __next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        popq    %%rsi\\n\" \"        jmp     *%%rax\\n\\n\");\n}\n\n// Nothing to do for the end of a file\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the %rsp and %rsp\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\" \"\\t.type\\t%s, @function\\n\", name, name);\n  fprintf(Outfile, \"%s:\\n\" \"\\tpushq\\t%%rbp\\n\" \"\\tmovq\\t%%rsp, %%rbp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->size);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\taddq\\t$%d,%%rsp\\n\", stackOffset);\n  fputs(\"\\tpopq\t%rbp\\n\" \"\\tret\\n\", Outfile);\n  cgfreeallregs(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = cgallocreg();\n\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", value, reglist[r]);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadvar(struct symtable *sym, int op) {\n  int r, postreg, offset = 1;\n\n  // Get a new register\n  r = cgallocreg();\n\n  // If the symbol is a pointer, use the size\n  // of the type that it points to as any\n  // increment or decrement. If not, it's one.\n  if (ptrtype(sym->type))\n    offset = typesize(value_at(sym->type), sym->ctype);\n\n  // Negate the offset for decrements\n  if (op == A_PREDEC || op == A_POSTDEC)\n    offset = -offset;\n\n  // If we have a pre-operation\n  if (op == A_PREINC || op == A_PREDEC) {\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    else\n      fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n\n    // and change the value at that address\n    switch (sym->size) {\n    case 1:\n      fprintf(Outfile, \"\\taddb\\t$%d,(%s)\\n\", offset, reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\taddl\\t$%d,(%s)\\n\", offset, reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\taddq\\t$%d,(%s)\\n\", offset, reglist[r]);\n      break;\n    }\n  }\n\n  // Now load the output register with the value\n  if (sym->class == C_LOCAL || sym->class == C_PARAM) {\n    switch (sym->size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovslq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n    }\n  } else {\n    switch (sym->size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzbq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovslq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmovq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n    }\n  }\n\n  // If we have a post-operation, get a new register\n  if (op == A_POSTINC || op == A_POSTDEC) {\n    postreg = cgallocreg();\n\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn,\n\t      reglist[postreg]);\n    else\n      fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name,\n\t      reglist[postreg]);\n\n    // and change the value at that address\n    switch (sym->size) {\n    case 1:\n      fprintf(Outfile, \"\\taddb\\t$%d,(%s)\\n\", offset, reglist[postreg]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\taddl\\t$%d,(%s)\\n\", offset, reglist[postreg]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\taddq\\t$%d,(%s)\\n\", offset, reglist[postreg]);\n      break;\n    }\n\n    // Finally, free the register\n    cgfreereg(postreg);\n  }\n\n  // Return the register with the value\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = cgallocreg();\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %s\\n\", label, reglist[r]);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\taddq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsubq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timulq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Divide or modulo the first register by the second and\n// return the number of the register with the result\nint cgdivmod(int r1, int r2, int op) {\n  fprintf(Outfile, \"\\tmovq\\t%s,%%rax\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidivq\\t%s\\n\", reglist[r2]);\n  if (op == A_DIVIDE)\n    fprintf(Outfile, \"\\tmovq\\t%%rax,%s\\n\", reglist[r1]);\n  else\n    fprintf(Outfile, \"\\tmovq\\t%%rdx,%s\\n\", reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Bitwise AND two registers\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tandq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Bitwise OR two registers\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\torq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Bitwise XOR two registers\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txorq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Shift left r1 by r2 bits\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshlq\\t%%cl, %s\\n\", reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Shift right r1 by r2 bits\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovb\\t%s, %%cl\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshrq\\t%%cl, %s\\n\", reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tnegq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnotq\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmovq\\t$%d, %s\\n\", val, reglist[r]);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch (op) {\n  case A_IF:\n  case A_WHILE:\n  case A_LOGAND:\n    fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n    break;\n  case A_LOGOR:\n    fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n    break;\n  default:\n    fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n    fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r], reglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id.\n// Pop off any arguments pushed on the stack.\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  fprintf(Outfile, \"\\tcall\\t%s@PLT\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6)\n    fprintf(Outfile, \"\\taddq\\t$%d, %%rsp\\n\", 8 * (numargs - 6));\n\n  // Unspill all the registers\n  cgunspillregs();\n\n  // Get a new register and copy the return value into it\n  outr = cgallocreg();\n  fprintf(Outfile, \"\\tmovq\\t%%rax, %s\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function call.\n// Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpushq\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r],\n\t    reglist[FIRSTPARAMREG - argposn + 1]);\n  }\n  cgfreereg(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsalq\\t$%d, %s\\n\", val, reglist[r]);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %s(%%rip)\\n\", reglist[r], sym->name);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %s(%%rip)\\n\", breglist[r], sym->name);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %s(%%rip)\\n\", dreglist[r], sym->name);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", sym->type);\n    }\n  return (r);\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmovq\\t%s, %d(%%rbp)\\n\", reglist[r], sym->st_posn);\n  } else\n    switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmovb\\t%s, %d(%%rbp)\\n\", breglist[r], sym->st_posn);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmovl\\t%s, %d(%%rbp)\\n\", dreglist[r], sym->st_posn);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n    }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\t.globl\\t%s\\n\", node->name);\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\t.long\\t%d\\n\", initvalue);\n      break;\n    case 8:\n      // Generate the pointer to a string literal. Treat a zero value\n      // as actually zero, not the label L0\n      if (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t  && initvalue != 0)\n\tfprintf(Outfile, \"\\t.quad\\tL%d\\n\", initvalue);\n      else\n\tfprintf(Outfile, \"\\t.quad\\t%d\\n\", initvalue);\n      break;\n    default:\n      for (i = 0; i < size; i++)\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label.\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n}\n\n// NUL terminate a global string\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2, int type) {\n  int size = cgprimsize(type);\n\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tcmpb\\t%s, %s\\n\", breglist[r2], breglist[r1]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tcmpl\\t%s, %s\\n\", dreglist[r2], dreglist[r1]);\n    break;\n  default:\n    fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  }\n\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzbq\\t%s, %s\\n\", breglist[r2], reglist[r2]);\n  cgfreereg(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label, int type) {\n  int size = cgprimsize(type);\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tcmpb\\t%s, %s\\n\", breglist[r2], breglist[r1]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tcmpl\\t%s, %s\\n\", dreglist[r2], dreglist[r1]);\n    break;\n  default:\n    fprintf(Outfile, \"\\tcmpq\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n  }\n\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  cgfreereg(r1);\n  cgfreereg(r2);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n      case P_CHAR:\n\tfprintf(Outfile, \"\\tmovzbl\\t%s, %%eax\\n\", breglist[reg]);\n\tbreak;\n      case P_INT:\n\tfprintf(Outfile, \"\\tmovl\\t%s, %%eax\\n\", dreglist[reg]);\n\tbreak;\n      case P_LONG:\n\tfprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n\tbreak;\n      default:\n\tfatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = cgallocreg();\n\n  if (sym->class == C_GLOBAL ||\n      sym->class == C_EXTERN || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tleaq\\t%s(%%rip), %s\\n\", sym->name, reglist[r]);\n  else\n    fprintf(Outfile, \"\\tleaq\\t%d(%%rbp), %s\\n\", sym->st_posn, reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value\n// it points at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovzbq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tmovslq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t(%s), %s\\n\", reglist[r], reglist[r]);\n    break;\n  default:\n    fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n  case 1:\n    fprintf(Outfile, \"\\tmovb\\t%s, (%s)\\n\", breglist[r1], reglist[r2]);\n    break;\n  case 4:\n    fprintf(Outfile, \"\\tmovl\\t%s, (%s)\\n\", dreglist[r1], reglist[r2]);\n    break;\n  case 8:\n    fprintf(Outfile, \"\\tmovq\\t%s, (%s)\\n\", reglist[r1], reglist[r2]);\n    break;\n  default:\n    fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\t.quad\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.quad\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.quad\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmovq\\t%s, %%rax\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tleaq\\tL%d(%%rip), %%rdx\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\t__switch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmovq\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n}\n\n// Output a gdb directive to say on which\n// source code line number the following\n// assembly code came from\nvoid cglinenum(int line) {\n  // fprintf(Outfile, \"\\t.loc 1 %d 0\\n\", line);\n}\n"
  },
  {
    "path": "62_Cleanup/cg_arm.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for ARMv6 on Raspberry Pi\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n\n// List of available registers and their names.\nstatic int freereg[4];\nstatic char *reglist[4] = { \"r4\", \"r5\", \"r6\", \"r7\" };\n\n// Set all registers as available\nvoid freeall_registers(void) {\n  freereg[0] = freereg[1] = freereg[2] = freereg[3] = 1;\n}\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nstatic int alloc_register(void) {\n  for (int i = 0; i < 4; i++) {\n    if (freereg[i]) {\n      freereg[i] = 0;\n      return (i);\n    }\n  }\n  fatal(\"Out of registers\");\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nstatic void free_register(int reg) {\n  if (freereg[reg] != 0)\n    fatald(\"Error trying to free register\", reg);\n  freereg[reg] = 1;\n}\n\n// We have to store large integer literal values in memory.\n// Keep a list of them which will be output in the postamble\n#define MAXINTS 1024\nint Intlist[MAXINTS];\nstatic int Intslot = 0;\n\n// Determine the offset of a large integer\n// literal from the .L3 label. If the integer\n// isn't in the list, add it.\nstatic void set_int_offset(int val) {\n  int offset = -1;\n\n  // See if it is already there\n  for (int i = 0; i < Intslot; i++) {\n    if (Intlist[i] == val) {\n      offset = 4 * i;\n      break;\n    }\n  }\n\n  // Not in the list, so add it\n  if (offset == -1) {\n    offset = 4 * Intslot;\n    if (Intslot == MAXINTS)\n      fatal(\"Out of int slots in set_int_offset()\");\n    Intlist[Intslot++] = val;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L3+%d\\n\", offset);\n}\n\n// Print out the assembly preamble\nvoid cgpreamble() {\n  freeall_registers();\n  fputs(\"\\t.text\\n\", Outfile);\n}\n\n// Print out the assembly postamble\nvoid cgpostamble() {\n\n  // Print out the global variables\n  fprintf(Outfile, \".L2:\\n\");\n  for (int i = 0; i < Globs; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      fprintf(Outfile, \"\\t.word %s\\n\", Symtable[i].name);\n  }\n\n  // Print out the integer literals\n  fprintf(Outfile, \".L3:\\n\");\n  for (int i = 0; i < Intslot; i++) {\n    fprintf(Outfile, \"\\t.word %d\\n\", Intlist[i]);\n  }\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(int id) {\n  char *name = Symtable[id].name;\n  fprintf(Outfile,\n\t  \"\\t.text\\n\"\n\t  \"\\t.globl\\t%s\\n\"\n\t  \"\\t.type\\t%s, \\%%function\\n\"\n\t  \"%s:\\n\" \"\\tpush\\t{fp, lr}\\n\"\n\t  \"\\tadd\\tfp, sp, #4\\n\"\n\t  \"\\tsub\\tsp, sp, #8\\n\" \"\\tstr\\tr0, [fp, #-8]\\n\", name, name, name);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(int id) {\n  cglabel(Symtable[id].endlabel);\n  fputs(\"\\tsub\\tsp, fp, #4\\n\" \"\\tpop\\t{fp, pc}\\n\" \"\\t.align\\t2\\n\", Outfile);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = alloc_register();\n\n  // If the literal value is small, do it with one instruction\n  if (value <= 1000)\n    fprintf(Outfile, \"\\tmov\\t%s, #%d\\n\", reglist[r], value);\n  else {\n    set_int_offset(value);\n    fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n  }\n  return (r);\n}\n\n// Determine the offset of a variable from the .L2\n// label. Yes, this is inefficient code.\nstatic void set_var_offset(int id) {\n  int offset = 0;\n  // Walk the symbol table up to id.\n  // Find S_VARIABLEs and add on 4 until\n  // we get to our variable\n\n  for (int i = 0; i < id; i++) {\n    if (Symtable[i].stype == S_VARIABLE)\n      offset += 4;\n  }\n  // Load r3 with this offset\n  fprintf(Outfile, \"\\tldr\\tr3, .L2+%d\\n\", offset);\n}\n\n\n// Load a value from a variable into a register.\n// Return the number of the register\nint cgloadglob(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s, %s\\n\", reglist[r1], reglist[r1],\n\t  reglist[r2]);\n  free_register(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\tmul\\t%s, %s, %s\\n\", reglist[r2], reglist[r1],\n\t  reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Divide the first register by the second and\n// return the number of the register with the result\nint cgdiv(int r1, int r2) {\n\n  // To do a divide: r0 holds the dividend, r1 holds the divisor.\n  // The quotient is in r0.\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tmov\\tr1, %s\\n\", reglist[r2]);\n  fprintf(Outfile, \"\\tbl\\t__aeabi_idiv\\n\");\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r1]);\n  free_register(r2);\n  return (r1);\n}\n\n// Call a function with one argument from the given register\n// Return the register with the result\nint cgcall(int r, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[r]);\n  fprintf(Outfile, \"\\tbl\\t%s\\n\", Symtable[id].name);\n  fprintf(Outfile, \"\\tmov\\t%s, r0\\n\", reglist[r]);\n  return (r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tlsl\\t%s, %s, #%d\\n\", reglist[r], reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, int id) {\n\n  // Get the offset to the variable\n  set_var_offset(id);\n\n  switch (Symtable[id].type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    case P_INT:\n    case P_LONG:\n    case P_CHARPTR:\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tstr\\t%s, [r3]\\n\", reglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorglob:\", Symtable[id].type);\n  }\n  return (r);\n}\n\n// Given a P_XXX type value, return the\n// size of a primitive type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (4);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n    case P_LONG:\n      return (4);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Generate a global symbol\nvoid cgglobsym(int id) {\n  int typesize;\n  // Get the size of the type\n  typesize = cgprimsize(Symtable[id].type);\n\n  fprintf(Outfile, \"\\t.data\\n\" \"\\t.globl\\t%s\\n\", Symtable[id].name);\n  switch (typesize) {\n    case 1:\n      fprintf(Outfile, \"%s:\\t.byte\\t0\\n\", Symtable[id].name);\n      break;\n    case 4:\n      fprintf(Outfile, \"%s:\\t.long\\t0\\n\", Symtable[id].name);\n      break;\n    default:\n      fatald(\"Unknown typesize in cgglobsym: \", typesize);\n  }\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"moveq\", \"movne\", \"movlt\", \"movgt\", \"movle\", \"movge\" };\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] =\n  { \"movne\", \"moveq\", \"movge\", \"movle\", \"movgt\", \"movlt\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #1\\n\", cmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\t%s, #0\\n\", invcmplist[ASTop - A_EQ], reglist[r2]);\n  fprintf(Outfile, \"\\tuxtb\\t%s, %s\\n\", reglist[r2], reglist[r2]);\n  free_register(r1);\n  return (r2);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tb\\tL%d\\n\", l);\n}\n\n// List of inverted branch instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *brlist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label) {\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", brlist[ASTop - A_EQ], label);\n  freeall_registers();\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, int id) {\n  fprintf(Outfile, \"\\tmov\\tr0, %s\\n\", reglist[reg]);\n  cgjump(Symtable[id].endlabel);\n}\n\n// Generate code to load the address of a global\n// identifier into a variable. Return a new register\nint cgaddress(int id) {\n  // Get a new register\n  int r = alloc_register();\n\n  // Get the offset to the variable\n  set_var_offset(id);\n  fprintf(Outfile, \"\\tmov\\t%s, r3\\n\", reglist[r]);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  switch (type) {\n    case P_CHARPTR:\n      fprintf(Outfile, \"\\tldrb\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case P_INTPTR:\n    case P_LONGPTR:\n      fprintf(Outfile, \"\\tldr\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  switch (type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tstrb\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    case P_INT:\n    case P_LONG:\n      fprintf(Outfile, \"\\tstr\\t%s, [%s]\\n\", reglist[r1], reglist[r2]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n"
  },
  {
    "path": "62_Cleanup/cgn.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg } currSeg = no_seg;\n\n// List of available registers and their names.\n// We need a list of byte and doubleword registers, too.\n// The list also includes the registers used to\n// hold function parameters\n#define NUMFREEREGS 4\n#define FIRSTPARAMREG 9\t\t// Position of first parameter register\nstatic int freereg[NUMFREEREGS];\nstatic char *reglist[] =\n { \"r10\",  \"r11\", \"r12\", \"r13\", \"r9\", \"r8\", \"rcx\", \"rdx\", \"rsi\",\n   \"rdi\"\n};\n\n// We also need the 8-bit and 32-bit register names\nstatic char *breglist[] =\n { \"r10b\",  \"r11b\", \"r12b\", \"r13b\", \"r9b\", \"r8b\", \"cl\", \"dl\", \"sil\",\n   \"dil\"\n};\n\nstatic char *dreglist[] =\n { \"r10d\",  \"r11d\", \"r12d\", \"r13d\", \"r9d\", \"r8d\", \"ecx\", \"edx\",\n  \"esi\", \"edi\"\n};\n\n// Switch to the text segment\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\tsection .text\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\n// Switch to the data segment\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\tsection .data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Store a register's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\tqword\\t[rbp+%d], %s\\n\", sym->st_posn,\n            reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\tbyte\\t[rbp+%d], %s\\n\", sym->st_posn,\n              breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\tdword\\t[rbp+%d], %s\\n\", sym->st_posn,\n              dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgstorlocal:\", sym->type);\n  }\n  return (r);\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      break;\n    default:\n      // Align whatever we have now on a 4-byte alignment\n      // I put the generic code here so it can be reused elsewhere\n      alignment = 4;\n      offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  }\n  return (offset);\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\n// Position of stack pointer offset relative to stack base pointer.\n// We need this to ensure it is aligned on a 16-byte boundary.\nstatic int stackOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int size) {\n  // Decrement the offset by a minimum of 4 bytes\n  // and allocate on the stack\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\n// Push and pop a register on/off the stack\nstatic void pushreg(int r) {\n  fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n}\n\nstatic void popreg(int r) {\n  fprintf(Outfile, \"\\tpop\\t%s\\n\", reglist[r]);\n}\n\n// Set all registers as available.\n// But if reg is positive, don't free that one.\n\nvoid cgfreeallregs(int keepreg) {\n  int i;\n  // fprintf(Outfile, \"; freeing all registers\\n\");\n  for (i = 0; i < NUMFREEREGS; i++)\n    if (i != keepreg)\n      freereg[i] = 1;\n}\n\n// When we need to spill a register, we choose\n// the following register and then cycle through\n// the remaining registers. The spillreg increments\n// continually, so we need to take a modulo NUMFREEREGS\n// on it.\nstatic int spillreg = 0;\n\n// Allocate a free register. Return the number of\n// the register. Die if no available registers.\nint cgallocreg(void) {\n  int reg;\n\n  for (reg = 0; reg < NUMFREEREGS; reg++) {\n    if (freereg[reg]) {\n      freereg[reg] = 0;\n      // fprintf(Outfile, \"; allocated register %s\\n\", reglist[reg]);\n      return (reg);\n    }\n  }\n  // We have no registers, so we must spill one\n  reg = (spillreg % NUMFREEREGS);\n  spillreg++;\n  // fprintf(Outfile, \"; spilling reg %s\\n\", reglist[reg]);\n  pushreg(reg);\n  return (reg);\n}\n\n// Return a register to the list of available registers.\n// Check to see if it's not already there.\nvoid cgfreereg(int reg) {\n  if (freereg[reg] != 0) {\n    //fprintf(Outfile, \"# error trying to free register %s\\n\", reglist[reg]);\n    fatald(\"Error trying to free register\", reg);\n  }\n  // If this was a spilled register, get it back\n  if (spillreg > 0) {\n    spillreg--;\n    reg = (spillreg % NUMFREEREGS);\n    // fprintf(Outfile, \"; unspilling reg %s\\n\", reglist[reg]);\n    popreg(reg);\n  } else {\n    // fprintf(Outfile, \"; freeing reg %s\\n\", reglist[reg]);\n    freereg[reg] = 1;\n  }\n}\n\n// Spill all registers on the stack\nvoid cgspillregs(void) {\n  int i;\n\n  for (i = 0; i < NUMFREEREGS; i++)\n    pushreg(i);\n}\n\n// Unspill all registers from the stack\nstatic void cgunspillregs(void) {\n  int i;\n\n  for (i = NUMFREEREGS - 1; i >= 0; i--)\n    popreg(i);\n}\n\n// Print out the assembly preamble\n// for one output file\nvoid cgpreamble(char *filename) {\n  cgfreeallregs(NOREG);\n  cgtextseg();\n  fprintf(Outfile, \";\\t%s\\n\", filename);\n  fprintf(Outfile,\n\t  \"; internal switch(expr) routine\\n\"\n\t  \"; rsi = switch table, rax = expr\\n\"\n\t  \"; from SubC: http://www.t3x.org/subc/\\n\"\n\t  \"\\n\"\n\t  \"__switch:\\n\"\n\t  \"        push   rsi\\n\"\n\t  \"        mov    rsi, rdx\\n\"\n\t  \"        mov    rbx, rax\\n\"\n\t  \"        cld\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rcx, rax\\n\"\n\t  \"__next:\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        mov    rdx, rax\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        cmp    rbx, rdx\\n\"\n\t  \"        jnz    __no\\n\"\n\t  \"        pop    rsi\\n\"\n\t  \"        jmp    rax\\n\"\n\t  \"__no:\\n\"\n\t  \"        loop   __next\\n\"\n\t  \"        lodsq\\n\"\n\t  \"        pop    rsi\\n\" \"        jmp     rax\\n\\n\");\n}\n\n// Nothing to do for the end of a file\nvoid cgpostamble() {\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int cnt;\n  int paramOffset = 16;\t\t// Any pushed params start at this stack offset\n  int paramReg = FIRSTPARAMREG;\t// Index to the first param register in above reg lists\n\n  // Output in the text segment, reset local offset\n  cgtextseg();\n  localOffset = 0;\n\n  // Output the function start, save the rsp and rbp\n//  if (sym->class == C_GLOBAL)\n  if(!sym->extinit) {\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", name);\n    sym->extinit = 1;\n  }\n  fprintf(Outfile,\n\t  \"%s:\\n\" \"\\tpush\\trbp\\n\"\n\t  \"\\tmov\\trbp, rsp\\n\", name);\n\n  // Copy any in-register parameters to the stack, up to six of them\n  // The remaining parameters are already on the stack\n  for (parm = sym->member, cnt = 1; parm != NULL; parm = parm->next, cnt++) {\n    if (cnt > 6) {\n      parm->st_posn = paramOffset;\n      paramOffset += 8;\n    } else {\n      parm->st_posn = newlocaloffset(parm->size);\n      cgstorlocal(paramReg--, parm);\n    }\n  }\n\n  // For the remainder, if they are a parameter then they are\n  // already on the stack. If only a local, make a stack position.\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);\n  }\n\n  // Align the stack pointer to be a multiple of 16\n  // less than its previous value\n  stackOffset = (localOffset + 15) & ~15;\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", -stackOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", stackOffset);\n  fputs(\"\\tpop\trbp\\n\" \"\\tret\\n\", Outfile);\n  cgfreeallregs(NOREG);\n}\n\n// Load an integer literal value into a register.\n// Return the number of the register.\n// For x86-64, we don't need to worry about the type.\nint cgloadint(int value, int type) {\n  // Get a new register\n  int r = cgallocreg();\n\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], value);\n  return (r);\n}\n\n// Load a value from a variable into a register.\n// Return the number of the register. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadvar(struct symtable *sym, int op) {\n  int r, postreg, offset = 1;\n\n  if(!sym->extinit) {\n    fprintf(Outfile, \"extern\\t%s\\n\", sym->name);\n    sym->extinit = 1;\n  }\n\n  // Get a new register\n  r = cgallocreg();\n\n  // If the symbol is a pointer, use the size\n  // of the type that it points to as any\n  // increment or decrement. If not, it's one.\n  if (ptrtype(sym->type))\n    offset = typesize(value_at(sym->type), sym->ctype);\n\n  // Negate the offset for decrements\n  if (op == A_PREDEC || op == A_POSTDEC)\n    offset = -offset;\n\n  // If we have a pre-operation\n  if (op == A_PREINC || op == A_PREDEC) {\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r], sym->st_posn);\n    else\n      fprintf(Outfile, \"\\tlea\\t%s, [%s]\\n\", reglist[r], sym->name);\n\n    // and change the value at that address\n    switch (sym->size) {\n      case 1:\n        fprintf(Outfile, \"\\tadd\\tbyte [%s], %d\\n\", reglist[r], offset);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tadd\\tdword [%s], %d\\n\", reglist[r], offset);\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tadd\\tqword [%s], %d\\n\", reglist[r], offset);\n        break;\n    }\n  }\n\n  // Now load the output register with the value\n  if (sym->class == C_LOCAL || sym->class == C_PARAM) {\n    switch (sym->size) {\n      case 1:\n        fprintf(Outfile, \"\\tmovzx\\t%s, byte [rbp+%d]\\n\", reglist[r], sym->st_posn);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tmovsxd\\t%s, dword [rbp+%d]\\n\", reglist[r], sym->st_posn);\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tmov\\t%s, [rbp+%d]\\n\", reglist[r], sym->st_posn);\n    }\n  } else {\n    switch (sym->size) {\n      case 1:\n        fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], sym->name);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tmovsxd\\t%s, dword [%s]\\n\", reglist[r], sym->name);\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], sym->name);\n    }\n  }\n\n  // If we have a post-operation, get a new register\n  if (op == A_POSTINC || op == A_POSTDEC) {\n    postreg = cgallocreg();\n\n    // Load the symbol's address\n    if (sym->class == C_LOCAL || sym->class == C_PARAM)\n      fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[postreg], sym->st_posn);\n    else\n      fprintf(Outfile, \"\\tlea\\t%s, [%s]\\n\", reglist[postreg], sym->name);\n\n    // and change the value at that address\n    switch (sym->size) {\n      case 1:\n        fprintf(Outfile, \"\\tadd\\tbyte [%s], %d\\n\", reglist[postreg], offset);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tadd\\tdword [%s], %d\\n\", reglist[postreg], offset);\n        break;\n      case 8:\n        fprintf(Outfile, \"\\tadd\\tqword [%s], %d\\n\", reglist[postreg], offset);\n        break;\n    }\n\n    // Finally, free the register\n    cgfreereg(postreg);\n  }\n\n  // Return the register with the value\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new register\nint cgloadglobstr(int label) {\n  // Get a new register\n  int r = cgallocreg();\n  fprintf(Outfile, \"\\tmov\\t%s, L%d\\n\", reglist[r], label);\n  return (r);\n}\n\n// Add two registers together and return\n// the number of the register with the result\nint cgadd(int r1, int r2) {\n  fprintf(Outfile, \"\\tadd\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Subtract the second register from the first and\n// return the number of the register with the result\nint cgsub(int r1, int r2) {\n  fprintf(Outfile, \"\\tsub\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Multiply two registers together and return\n// the number of the register with the result\nint cgmul(int r1, int r2) {\n  fprintf(Outfile, \"\\timul\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Divide or modulo the first register by the second and\n// return the number of the register with the result\nint cgdivmod(int r1, int r2, int op) {\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[r1]);\n  fprintf(Outfile, \"\\tcqo\\n\");\n  fprintf(Outfile, \"\\tidiv\\t%s\\n\", reglist[r2]);\n  if (op == A_DIVIDE)\n    fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[r1]);\n  else\n    fprintf(Outfile, \"\\tmov\\t%s, rdx\\n\", reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Bitwise AND two registers\nint cgand(int r1, int r2) {\n  fprintf(Outfile, \"\\tand\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Bitwise OR two registers\nint cgor(int r1, int r2) {\n  fprintf(Outfile, \"\\tor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Bitwise XOR two registers\nint cgxor(int r1, int r2) {\n  fprintf(Outfile, \"\\txor\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Shift left r1 by r2 bits\nint cgshl(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshl\\t%s, cl\\n\", reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Shift right r1 by r2 bits\nint cgshr(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\tcl, %s\\n\", breglist[r2]);\n  fprintf(Outfile, \"\\tshr\\t%s, cl\\n\", reglist[r1]);\n  cgfreereg(r2);\n  return (r1);\n}\n\n// Negate a register's value\nint cgnegate(int r) {\n  fprintf(Outfile, \"\\tneg\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Invert a register's value\nint cginvert(int r) {\n  fprintf(Outfile, \"\\tnot\\t%s\\n\", reglist[r]);\n  return (r);\n}\n\n// Logically negate a register's value\nint cglognot(int r) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  fprintf(Outfile, \"\\tsete\\t%s\\n\", breglist[r]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r], breglist[r]);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given register\nvoid cgloadboolean(int r, int val) {\n  fprintf(Outfile, \"\\tmov\\t%s, %d\\n\", reglist[r], val);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label) {\n  fprintf(Outfile, \"\\ttest\\t%s, %s\\n\", reglist[r], reglist[r]);\n  switch (op) {\n    case A_IF:\n    case A_WHILE:\n    case A_LOGAND:\n      fprintf(Outfile, \"\\tje\\tL%d\\n\", label);\n      break;\n    case A_LOGOR:\n      fprintf(Outfile, \"\\tjne\\tL%d\\n\", label);\n      break;\n    default:\n      fprintf(Outfile, \"\\tsetnz\\t%s\\n\", breglist[r]);\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte %s\\n\", reglist[r], breglist[r]);\n  }\n  return (r);\n}\n\n// Call a function with the given symbol id.\n// Pop off any arguments pushed on the stack.\n// Return the register with the result\nint cgcall(struct symtable *sym, int numargs) {\n  int outr;\n\n  // Call the function\n  if(!sym->extinit) {\n    fprintf(Outfile, \"extern\\t%s\\n\", sym->name);\n    sym->extinit = 1;\n  }\n  fprintf(Outfile, \"\\tcall\\t%s\\n\", sym->name);\n\n  // Remove any arguments pushed on the stack\n  if (numargs > 6) \n    fprintf(Outfile, \"\\tadd\\trsp, %d\\n\", 8 * (numargs - 6));\n\n  // Unspill all the registers\n  cgunspillregs();\n\n  // Get a new register and copy the return value into it\n  outr = cgallocreg();\n  fprintf(Outfile, \"\\tmov\\t%s, rax\\n\", reglist[outr]);\n  return (outr);\n}\n\n// Given a register with an argument value,\n// copy this argument into the argposn'th\n// parameter in preparation for a future function call.\n// Note that argposn is 1, 2, 3, 4, ..., never zero.\nvoid cgcopyarg(int r, int argposn) {\n\n  // If this is above the sixth argument, simply push the\n  // register on the stack. We rely on being called with\n  // successive arguments in the correct order for x86-64\n  if (argposn > 6) {\n    fprintf(Outfile, \"\\tpush\\t%s\\n\", reglist[r]);\n  } else {\n    // Otherwise, copy the value into one of the six registers\n    // used to hold parameter values\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", \n\t    reglist[FIRSTPARAMREG - argposn + 1], reglist[r]);\n  }\n  cgfreereg(r);\n}\n\n// Shift a register left by a constant\nint cgshlconst(int r, int val) {\n  fprintf(Outfile, \"\\tsal\\t%s, %d\\n\", reglist[r], val);\n  return (r);\n}\n\n// Store a register's value into a variable\nint cgstorglob(int r, struct symtable *sym) {\n  if(!sym->extinit) {\n    fprintf(Outfile, \"extern\\t%s\\n\", sym->name);\n    sym->extinit = 1;\n  }\n  if (cgprimsize(sym->type) == 8) {\n    fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, reglist[r]);\n  } else\n  switch (sym->type) {\n    case P_CHAR:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, breglist[r]);\n      break;\n    case P_INT:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", sym->name, dreglist[r]);\n      break;\n    default:\n      fatald(\"Bad type in cgloadglob:\", sym->type);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"\\tglobal\\t%s\\n\", node->name);\n  if(!node->extinit) {\n    node->extinit = 1;\n  }\n  fprintf(Outfile, \"%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    // original version\n    switch(size) {\n      case 1:\n        fprintf(Outfile, \"\\tdb\\t%d\\n\", initvalue);\n        break;\n      case 4:\n        fprintf(Outfile, \"\\tdd\\t%d\\n\", initvalue);\n        break;\n      case 8:\n        // Generate the pointer to a string literal.  Treat a zero value\n        // as actually zero, not the label L0\n        if (node->initlist != NULL && type == pointer_to(P_CHAR) && initvalue != 0)\n          fprintf(Outfile, \"\\tdq\\tL%d\\n\", initvalue);\n        else\n          fprintf(Outfile, \"\\tdq\\t%d\\n\", initvalue);\n        break;\n      default:\n        for (i = 0; i < size; i++) \n          fprintf(Outfile, \"\\tdb\\t0\\n\");\n    }\n  }\n\n}\n\n// Generate a global string and its start label.\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\tdb\\t%d\\n\", *cptr);\n  }\n}\n\n// NULL terminate a global string\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \"\\tdb\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"sete\", \"setne\", \"setl\", \"setg\", \"setle\", \"setge\" };\n\n// Compare two registers and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2, int type) {\n  int size = cgprimsize(type);\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", breglist[r1], breglist[r2]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", dreglist[r1], dreglist[r2]);\n      break;\n    default:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  }\n\n  fprintf(Outfile, \"\\t%s\\t%s\\n\", cmplist[ASTop - A_EQ], breglist[r2]);\n  fprintf(Outfile, \"\\tmovzx\\t%s, %s\\n\", reglist[r2], breglist[r2]);\n  cgfreereg(r1);\n  return (r2);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tjmp\\tL%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"jne\", \"je\", \"jge\", \"jle\", \"jg\", \"jl\" };\n\n// Compare two registers and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label, int type) {\n  int size = cgprimsize(type);\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", breglist[r1], breglist[r2]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", dreglist[r1], dreglist[r2]);\n      break;\n    default:\n      fprintf(Outfile, \"\\tcmp\\t%s, %s\\n\", reglist[r1], reglist[r2]);\n  }\n\n  fprintf(Outfile, \"\\t%s\\tL%d\\n\", invcmplist[ASTop - A_EQ], label);\n  cgfreereg(r1);\n  cgfreereg(r2);\n  return (NOREG);\n}\n\n// Widen the value in the register from the old\n// to the new type, and return a register with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  // Nothing to do\n  return (r);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG) {\n    // Deal with pointers here as we can't put them in\n    // the switch statement\n    if (ptrtype(sym->type))\n      fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n    else {\n      // Generate code depending on the function's type\n      switch (sym->type) {\n        case P_CHAR:\n          fprintf(Outfile, \"\\tmovzx\\teax, %s\\n\", breglist[reg]);\n          break;\n        case P_INT:\n          fprintf(Outfile, \"\\tmov\\teax, %s\\n\", dreglist[reg]);\n          break;\n        case P_LONG:\n          fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n          break;\n        default:\n          fatald(\"Bad function type in cgreturn:\", sym->type);\n      }\n    }\n  }\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier into a variable. Return a new register\nint cgaddress(struct symtable *sym) {\n  int r = cgallocreg();\n\n  if (!sym->extinit) {\n    fprintf(Outfile, \"extern\\t%s\\n\", sym->name);\n    sym->extinit = 1;\n  }\n  if (sym->class == C_GLOBAL ||\n      sym->class == C_EXTERN || sym->class == C_STATIC)\n    fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r], sym->name);\n  else\n    fprintf(Outfile, \"\\tlea\\t%s, [rbp+%d]\\n\", reglist[r],\n            sym->st_posn);\n  return (r);\n}\n\n// Dereference a pointer to get the value it\n// pointing at into the same register\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmovzx\\t%s, byte [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmovsx\\t%s, dword [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t%s, [%s]\\n\", reglist[r], reglist[r]);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (r);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  //Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tmov\\t[%s], byte %s\\n\", reglist[r2], breglist[r1]);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tmov\\t[%s], dword %s\\n\", reglist[r2], dreglist[r1]);\n      break;\n    case 8:\n      fprintf(Outfile, \"\\tmov\\t[%s], %s\\n\", reglist[r2], reglist[r1]);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate a switch jump table and the code to\n// load the registers and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch table\n  label = genlabel();\n  cglabel(label);\n\n  // Heuristic. If we have no cases, create one case\n  // which points to the default case\n  if (casecount == 0) {\n    caseval[0] = 0;\n    caselabel[0] = defaultlabel;\n    casecount = 1;\n  }\n  // Generate the switch jump table.\n  fprintf(Outfile, \"\\tdq\\t%d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\tdq\\t%d, L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\tdq\\tL%d\\n\", defaultlabel);\n\n  // Load the specific registers\n  cglabel(toplabel);\n  fprintf(Outfile, \"\\tmov\\trax, %s\\n\", reglist[reg]);\n  fprintf(Outfile, \"\\tmov\\trdx, L%d\\n\", label);\n  fprintf(Outfile, \"\\tjmp\\t__switch\\n\");\n}\n\n// Move value between registers\nvoid cgmove(int r1, int r2) {\n  fprintf(Outfile, \"\\tmov\\t%s, %s\\n\", reglist[r2], reglist[r1]);\n}\n\n// Output a gdb directive to say on which\n// source code line number the following\n// assembly code came from (not with nasm)\nvoid cglinenum(int line) {\n  //fprintf(Outfile, \";\\t.loc 1 %d 0\\n\", line);\n}\n"
  },
  {
    "path": "62_Cleanup/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Linestart;\t\t     \t// True if at start of a line\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\nextern char *Tstring[];\t\t\t// List of token strings\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_dumpsym;\t\t// If true, dump the symbol table\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "62_Cleanup/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Get the type inside the parentheses\n  type = parse_stars(parse_type(ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return (type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree = optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type = tree->type;\n    tree = tree->left;\n  }\n\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return (tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue == 0)\n      return (0);\n  }\n\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return (tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a pointer to a symbol that may already exist\n// return true if this symbol doesn't exist. We use\n// this function to convert externs into globals\nstatic int is_new_symbol(struct symtable *sym, int class, \n\t\t  int type, struct symtable *ctype) {\n\n  // There is no existing symbol, thus is new\n  if (sym==NULL) return(1);\n\n  // global versus extern: if they match that it's not new\n  // and we can convert the class to global\n  if ((sym->class== C_GLOBAL && class== C_EXTERN)\n      || (sym->class== C_EXTERN && class== C_GLOBAL)) {\n\n      // If the types don't match, there's a problem\n      if (type != sym->type)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // Struct/unions, also compare the ctype\n      if (type >= P_STRUCT && ctype != sym->ctype)\n        fatals(\"Type mismatch between global/extern\", sym->name);\n\n      // If we get to here, the types match, so mark the symbol\n      // as global\n      sym->class= C_GLOBAL;\n      // Return that symbol is not new\n      return(0);\n  }\n\n  // It must be a duplicate symbol if we get here\n  fatals(\"Duplicate global variable declaration\", sym->name);\n  return(-1);\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree = NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, type, ctype))\n        sym = addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym = addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym = addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist = (int *) malloc(sizeof(int));\n      sym->initlist[0] = parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym->ctype, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, varnode->ctype, 0);\n      if (exprnode == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode->ctype, exprnode,\n\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an array variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym;\t// New symbol table entry\n  int nelems = -1;\t// Assume the number of elements won't be given\n  int maxelems;\t\t// The maximum number of elements in the init list\n  int *initlist;\t// The list of initial elements \n  int i = 0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See if we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems = parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym= findglob(varname);\n      if (is_new_symbol(sym, class, pointer_to(type), ctype))\n        sym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class, 0, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, pointer_to(type), ctype, S_ARRAY, 0);\n      break;\n    default:\n      fatal(\"Declaration of array parameters is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems = nelems;\n    else\n      maxelems = TABLE_INCREMENT;\n    initlist = (int *) malloc(maxelems * sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n\tfatal(\"Too many values in initialisation list\");\n\n      initlist[i++] = parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n\tmaxelems += TABLE_INCREMENT;\n\tinitlist = (int *) realloc(initlist, maxelems * sizeof(int));\n      }\n\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n\tscan(&Token);\n\tbreak;\n      }\n\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j = i; j < sym->nelems; j++)\n      initlist[j] = 0;\n\n    if (i > nelems)\n      nelems = i;\n    sym->initlist = initlist;\n  }\n\n  // Set the size of the array and the number of elements\n  // Only externs can have no elements.\n  if (class != C_EXTERN && nelems<=0)\n    fatals(\"Array must have non-zero elements\", sym->name);\n\n  sym->nelems = nelems;\n  sym->size = sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n\tparamcnt = 0;\n\tscan(&Token);\n\tbreak;\n      }\n    }\n\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel, paramcnt;\n  int linenum= Line;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumption: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // If the declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ...\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, ctype, tree, oldfuncsym, endlabel);\n  tree->linenum= linenum;\n\n  // Do optimisations on the AST tree\n  tree = optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t = declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t == -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead == NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name = NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have static/extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the symbol's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET) {\n    sym = array_declaration(varname, type, ctype, class);\n    *tree= NULL;\t// Local arrays are not initialised\n  } else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree;\n  *gluetree = NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n\tfatal(\"Function definition not at global level\");\n      return (type);\n    }\n\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree == NULL)\n      *gluetree = tree;\n    else\n      *gluetree =\n\tmkastnode(A_GLUE, P_NONE, NULL, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n\n  return(0);\t// Keep -Wall happy\n}\n\n// Parse one or more global declarations,\n// either variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype= NULL;\n  struct ASTnode *unused;\n\n  // Loop parsing one declaration list until the end of file\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n\n    // Skip any separating semicolons\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "62_Cleanup/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int level);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop);\nvoid genpreamble(char *filename);\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue, int append);\nvoid genglobstrend(void);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nint cgallocreg(void);\nvoid cgfreeallregs(int keepreg);\nvoid cgfreereg(int reg);\nvoid cgspillregs(void);\nvoid cgpreamble(char *filename);\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadvar(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2);\nint cgsub(int r1, int r2);\nint cgmul(int r1, int r2);\nint cgdivmod(int r1, int r2, int op);\nint cgshlconst(int r, int val);\nint cgcall(struct symtable *sym, int numargs);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue, int append);\nvoid cgglobstrend(void);\nint cgcompare_and_set(int ASTop, int r1, int r2, int type);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label, int type);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r);\nint cginvert(int r);\nint cglognot(int r);\nvoid cgloadboolean(int r, int val);\nint cgboolean(int r, int op, int label);\nint cgand(int r1, int r2);\nint cgor(int r1, int r2);\nint cgxor(int r1, int r2);\nint cgshl(int r1, int r2);\nint cgshr(int r1, int r2);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2);\nvoid cglinenum(int line);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\nvoid dumptable(struct symtable *head, char *name, int indent);\nvoid dumpsymtables(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(struct symtable **ctype);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n\t\t\t    struct symtable *rctype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "62_Cleanup/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n#include \"incdir.h\"\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#ifdef __NASM__\n#define ASCMD \"nasm -g -f elf64 -w-ptr -o \"\n#define LDCMD \"cc -g -no-pie -fno-plt -Wall -o \"\n#else\n#define ASCMD \"as -g -o \"\n#define LDCMD \"cc -g -o \"\n#endif\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\n  T_ASSTAR, T_ASSLASH, T_ASMOD,\n  T_QUESTION, T_LOGOR, T_LOGAND,\n  T_OR, T_XOR, T_AMPER,\n  T_EQ, T_NE,\n  T_LT, T_GT, T_LE, T_GE,\n  T_LSHIFT, T_RSHIFT,\n  T_PLUS, T_MINUS, T_STAR, T_SLASH, T_MOD,\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\n  T_ARROW, T_COLON\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR,\t\t\t//  1\n  A_ASSLASH, A_ASMOD, A_TERNARY, A_LOGOR,\t\t\t//  5\n  A_LOGAND, A_OR, A_XOR, A_AND, A_EQ, A_NE, A_LT,\t\t//  9\n  A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\t\t\t\t// 16\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_MOD,\t\t// 21\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\t\t\t\t// 26\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\t\t\t// 30\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\t\t\t\t// 35\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\t\t\t// 39\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\t\t// 43\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\t\t// 48\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n#ifdef __NASM__\n  int extinit;\n#endif\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n  int linenum;\t\t\t// Line number from where this node comes\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "62_Cleanup/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree =\n      mkastnode(A_GLUE, P_NONE, NULL, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree =\n    mkastunary(A_FUNCCALL, funcptr->type, funcptr->ctype, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(struct ASTnode *left) {\n  struct ASTnode *right;\n\n  // Check that the sub-tree is a pointer\n  if (!ptrtype(left->type))\n    fatal(\"Not an array or pointer\");\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, left->ctype, A_ADD);\n\n  // Return an AST tree where the array's base has the offset added to it,\n  // and dereference the element. Still an lvalue at this point.\n  left =\n    mkastnode(A_ADD, left->type, left->ctype, left, NULL, right, NULL, 0);\n  left =\n    mkastunary(A_DEREF, value_at(left->type), left->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(struct ASTnode *left, int withpointer) {\n  struct ASTnode *right;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the left AST tree is a pointer to struct or union\n  if (withpointer && left->type != pointer_to(P_STRUCT)\n      && left->type != pointer_to(P_UNION))\n    fatal(\"Expression is not a pointer to a struct/union\");\n\n  // Or, check that the left AST tree is a struct or union.\n  // If so, change it from an A_IDENT to an A_ADDR so that\n  // we get the base address, not the value at this address.\n  if (!withpointer) {\n    if (left->type == P_STRUCT || left->type == P_UNION)\n      left->op = A_ADDR;\n    else\n      fatal(\"Expression is not a struct/union\");\n  }\n\n  // Get the details of the composite type\n  typeptr = left->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_INT, NULL, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left =\n    mkastnode(A_ADD, pointer_to(m->type), m->ctype, left, NULL, right, NULL,\n\t      0);\n  left = mkastunary(A_DEREF, m->type, m->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse a parenthesised expression and\n// return an AST node representing it.\nstatic struct ASTnode *paren_expression(int ptp) {\n  struct ASTnode *n;\n  int type = 0;\n  struct symtable *ctype = NULL;\n\n  // Beginning of a parenthesised expression, skip the '('.\n  scan(&Token);\n\n  // If the token after is a type identifier, this is a cast expression\n  switch (Token.token) {\n  case T_IDENT:\n    // We have to see if the identifier matches a typedef.\n    // If not, treat it as an expression.\n    if (findtypedef(Text) == NULL) {\n      n = binexpr(0);\t// ptp is zero as expression inside ( )\n      break;\n    }\n  case T_VOID:\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n  case T_STRUCT:\n  case T_UNION:\n  case T_ENUM:\n    // Get the type inside the parentheses\n    type = parse_cast(&ctype);\n\n    // Skip the closing ')' and then parse the following expression\n    rparen();\n\n  default:\n    n = binexpr(ptp);\t\t// Scan in the expression. We pass in ptp\n\t\t\t\t// as the cast doesn't change the\n\t\t\t\t// expression's precedence\n  }\n\n  // We now have at least an expression in n, and possibly a non-zero type\n  // in type if there was a cast. Skip the closing ')' if there was no cast.\n  if (type == 0)\n    rparen();\n  else\n    // Otherwise, make a unary AST node for the cast\n    n = mkastunary(A_CAST, type, ctype, n, NULL, 0);\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(int ptp) {\n  struct ASTnode *n;\n  struct symtable *enumptr;\n  struct symtable *varptr;\n  int id;\n  int type = 0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type = parse_stars(parse_type(&ctype, &class));\n\n    // Get the type's size\n    size = typesize(type, ctype);\n    rparen();\n\n    // Make a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, NULL, size));\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    // Make it a P_CHAR if it's within the P_CHAR range\n    if (Token.intvalue >= 0 && Token.intvalue < 256)\n      n = mkastleaf(A_INTLIT, P_CHAR, NULL, NULL, Token.intvalue);\n    else\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, generate the assembly for it.\n    id = genglobstr(Text, 0);\n\n    // For successive STRLIT tokens, append their contents\n    // to this one\n    while (1) {\n      scan(&Peektoken);\n      if (Peektoken.token != T_STRLIT) break;\n      genglobstr(Text, 1);\n      scan(&Token);\t// To skip it properly\n    }\n\n    // Now make a leaf AST node for it. id is the string's label.\n    genglobstrend();\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, NULL, id);\n    break;\n\n  case T_IDENT:\n    // If the identifier matches an enum value,\n    // return an A_INTLIT node\n    if ((enumptr = findenumval(Text)) != NULL) {\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, enumptr->st_posn);\n      break;\n    }\n\n    // See if this identifier exists as a symbol. For arrays, set rvalue to 1.\n    if ((varptr = findsymbol(Text)) == NULL)\n      fatals(\"Unknown variable or function\", Text);\n    switch (varptr->stype) {\n    case S_VARIABLE:\n      n = mkastleaf(A_IDENT, varptr->type, varptr->ctype, varptr, 0);\n      break;\n    case S_ARRAY:\n      n = mkastleaf(A_ADDR, varptr->type, varptr->ctype, varptr, 0);\n      n->rvalue = 1;\n      break;\n    case S_FUNCTION:\n      // Function call, see if the next token is a left parenthesis\n      scan(&Token);\n      if (Token.token != T_LPAREN)\n\tfatals(\"Function name used without parentheses\", Text);\n      return (funccall());\n    default:\n      fatals(\"Identifier not a scalar or array variable\", Text);\n    }\n\n    break;\n\n  case T_LPAREN:\n    return (paren_expression(ptp));\n\n  default:\n    fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(int ptp) {\n  struct ASTnode *n;\n\n  // Get the primary expression\n  n = primary(ptp);\n\n  // Loop until there are no more postfix operators\n  while (1) {\n    switch (Token.token) {\n    case T_LBRACKET:\n      // An array reference\n      n = array_access(n);\n      break;\n\n    case T_DOT:\n      // Access into a struct or union\n      n = member_access(n, 0);\n      break;\n\n    case T_ARROW:\n      // Pointer access into a struct or union\n      n = member_access(n, 1);\n      break;\n\n    case T_INC:\n      // Post-increment: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot ++ on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTINC;\n      break;\n\n    case T_DEC:\n      // Post-decrement: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot -- on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTDEC;\n      break;\n\n    default:\n      return (n);\n    }\n  }\n\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_MOD)\n    return (tokentype);\n  fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10,\t\t\t// T_ASMINUS, T_ASSTAR,\n  10, 10,\t\t\t// T_ASSLASH, T_ASMOD,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110, 110\t\t\t// T_STAR, T_SLASH, T_MOD\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_MOD)\n    fatals(\"Token with no precedence in op_precedence:\", Tstring[tokentype]);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (prec);\n}\n\n// prefix_expression: postfix_expression\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstatic struct ASTnode *prefix(int ptp) {\n  struct ASTnode *tree;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Prevent '&' being performed on an array\n    if (tree->sym->stype == S_ARRAY)\n      fatal(\"& operator cannot be performed on an array\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression.\n    // Make it an rvalue\n    scan(&Token);\n    tree = prefix(ptp);\n    tree->rvalue= 1;\n\n    // Ensure the tree's type is a pointer\n    if (!ptrtype(tree->type))\n      fatal(\"* operator must be followed by an expression of pointer type\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree =\n      mkastunary(A_DEREF, value_at(tree->type), tree->ctype, tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this if needed to int so that it's signed\n    tree->rvalue = 1;\n    if (tree->type == P_CHAR)\n      tree->type = P_INT;\n    tree = mkastunary(A_NEGATE, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  default:\n    tree = postfix(ptp);\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix(ptp);\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp = binexpr(0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. XXX We should also\n      // consider the third expression's type.\n      return (mkastnode\n\t      (A_TERNARY, right->type, right->ctype, left, right, ltemp,\n\t       NULL, 0));\n\n    case A_ASSIGN:\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, left->ctype, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n      break;\n\n    default:\n      // We are not doing a ternary or assignment, so both trees should\n      // be rvalues. Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, right->ctype, ASTop);\n      rtemp = modify_type(right, left->type, left->ctype, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left->ctype, left, NULL,\n\t\tright, NULL, 0);\n\n    // Some operators produce an int result regardless of their operands\n    switch (binastop(tokentype)) {\n    case A_LOGOR:\n    case A_LOGAND:\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      left->type = P_INT;\n    }\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "62_Cleanup/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\nstatic void update_line(struct ASTnode *n) {\n  // Output the line into the assembly if we've\n  // changed the line number in the AST node\n  if (n->linenum != 0 && Line != n->linenum) {\n    Line = n->linenum;\n    cglinenum(Line);\n  }\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(n->left, Lend, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  struct ASTnode *c;\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs(reg);\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    cglabel(caselabel[i]);\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    if (c->left)\n      genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n    genfreeregs(NOREG);\n  }\n\n  // Ensure the last case jumps past the switch table\n  cgjump(Lend);\n\n  // Now output the switch table and the end label.\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for an\n// A_LOGAND or A_LOGOR operation\nstatic int gen_logandor(struct ASTnode *n) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n  int reg;\n\n  // Generate the code for the left expression\n  // followed by the jump to the false label\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(NOREG);\n\n  // Generate the code for the right expression\n  // followed by the jump to the false label\n  reg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgboolean(reg, n->op, Lfalse);\n  genfreeregs(reg);\n\n  // We didn't jump so set the right boolean value\n  if (n->op == A_LOGAND) {\n    cgloadboolean(reg, 1);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 0);\n  } else {\n    cgloadboolean(reg, 0);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 1);\n  }\n  cglabel(Lend);\n  return (reg);\n}\n\n// Generate the code to copy the arguments of a\n// function call to its parameters, then call the\n// function itself. Return the register that holds \n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree = n->left;\n  int reg;\n  int numargs = 0;\n\n  // Save the registers before we copy the arguments\n  cgspillregs();\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the\n  // first\n  while (gluetree) {\n    // Calculate the expression's value\n    reg = genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    // Copy this into the n'th function parameter: size is 1, 2, 3, ...\n    cgcopyarg(reg, gluetree->a_size);\n    // Keep the first (highest) number of arguments\n    if (numargs == 0)\n      numargs = gluetree->a_size;\n    gluetree = gluetree->left;\n  }\n\n  // Call the function, clean up the stack (based on numargs),\n  // and return its result\n  return (cgcall(n->sym, numargs));\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  // genfreeregs(NOREG);\n\n  // Get a register to hold the result of the two expressions\n  reg = cgallocreg();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  cgfreereg(expreg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg);\n  cgfreereg(expreg);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg = NOREG, rightreg = NOREG;\n\n  // Empty tree, do nothing\n  if (n == NULL)\n    return (NOREG);\n\n  // Update the line number in the output\n  update_line(n);\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n  case A_IF:\n    return (genIF(n, looptoplabel, loopendlabel));\n  case A_WHILE:\n    return (genWHILE(n));\n  case A_SWITCH:\n    return (genSWITCH(n));\n  case A_FUNCCALL:\n    return (gen_funccall(n));\n  case A_TERNARY:\n    return (gen_ternary(n));\n  case A_LOGOR:\n    return (gen_logandor(n));\n  case A_LOGAND:\n    return (gen_logandor(n));\n  case A_GLUE:\n    // Do each child statement, and free the\n    // registers after each child\n    if (n->left != NULL)\n      genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    if (n->right != NULL)\n      genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    return (NOREG);\n  case A_FUNCTION:\n    // Generate the function's preamble before the code\n    // in the child sub-tree\n    cgfuncpreamble(n->sym);\n    genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n    cgfuncpostamble(n->sym);\n    return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values\n  if (n->left)\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  if (n->right)\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n\n  switch (n->op) {\n  case A_ADD:\n    return (cgadd(leftreg, rightreg));\n  case A_SUBTRACT:\n    return (cgsub(leftreg, rightreg));\n  case A_MULTIPLY:\n    return (cgmul(leftreg, rightreg));\n  case A_DIVIDE:\n    return (cgdivmod(leftreg, rightreg, A_DIVIDE));\n  case A_MOD:\n    return (cgdivmod(leftreg, rightreg, A_MOD));\n  case A_AND:\n    return (cgand(leftreg, rightreg));\n  case A_OR:\n    return (cgor(leftreg, rightreg));\n  case A_XOR:\n    return (cgxor(leftreg, rightreg));\n  case A_LSHIFT:\n    return (cgshl(leftreg, rightreg));\n  case A_RSHIFT:\n    return (cgshr(leftreg, rightreg));\n  case A_EQ:\n  case A_NE:\n  case A_LT:\n  case A_GT:\n  case A_LE:\n  case A_GE:\n    // If the parent AST node is an A_IF, A_WHILE or A_TERNARY,\n    // generate a compare followed by a jump. Otherwise, compare\n    // registers and set one to 1 or 0 based on the comparison.\n    if (parentASTop == A_IF || parentASTop == A_WHILE ||\n\tparentASTop == A_TERNARY)\n      return (cgcompare_and_jump\n\t      (n->op, leftreg, rightreg, iflabel, n->left->type));\n    else\n      return (cgcompare_and_set(n->op, leftreg, rightreg, n->left->type));\n  case A_INTLIT:\n    return (cgloadint(n->a_intvalue, n->type));\n  case A_STRLIT:\n    return (cgloadglobstr(n->a_intvalue));\n  case A_IDENT:\n    // Load our value if we are an rvalue\n    // or we are being dereferenced\n    if (n->rvalue || parentASTop == A_DEREF) {\n      return (cgloadvar(n->sym, n->op));\n    } else\n      return (NOREG);\n  case A_ASPLUS:\n  case A_ASMINUS:\n  case A_ASSTAR:\n  case A_ASSLASH:\n  case A_ASMOD:\n  case A_ASSIGN:\n\n    // For the '+=' and friends operators, generate suitable code\n    // and get the register with the result. Then take the left child,\n    // make it the right child so that we can fall into the assignment code.\n    switch (n->op) {\n    case A_ASPLUS:\n      leftreg = cgadd(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASMINUS:\n      leftreg = cgsub(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASSTAR:\n      leftreg = cgmul(leftreg, rightreg);\n      n->right = n->left;\n      break;\n    case A_ASSLASH:\n      leftreg = cgdivmod(leftreg, rightreg, A_DIVIDE);\n      n->right = n->left;\n      break;\n    case A_ASMOD:\n      leftreg = cgdivmod(leftreg, rightreg, A_MOD);\n      n->right = n->left;\n      break;\n    }\n\n    // Now into the assignment code\n    // Are we assigning to an identifier or through a pointer?\n    switch (n->right->op) {\n    case A_IDENT:\n      if (n->right->sym->class == C_GLOBAL ||\n\t  n->right->sym->class == C_EXTERN ||\n\t  n->right->sym->class == C_STATIC)\n\treturn (cgstorglob(leftreg, n->right->sym));\n      else\n\treturn (cgstorlocal(leftreg, n->right->sym));\n    case A_DEREF:\n      return (cgstorderef(leftreg, rightreg, n->right->type));\n    default:\n      fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n    }\n  case A_WIDEN:\n    // Widen the child's type to the parent's type\n    return (cgwiden(leftreg, n->left->type, n->type));\n  case A_RETURN:\n    cgreturn(leftreg, Functionid);\n    return (NOREG);\n  case A_ADDR:\n    // If we have a symbol, get its address. Otherwise,\n    // the left register already has the address because\n    // it's a member access\n    if (n->sym != NULL)\n      return (cgaddress(n->sym));\n    else\n      return (leftreg);\n  case A_DEREF:\n    // If we are an rvalue, dereference to get the value we point at,\n    // otherwise leave it for A_ASSIGN to store through the pointer\n    if (n->rvalue)\n      return (cgderef(leftreg, n->left->type));\n    else\n      return (leftreg);\n  case A_SCALE:\n    // Small optimisation: use shift if the\n    // scale value is a known power of two\n    switch (n->a_size) {\n    case 2:\n      return (cgshlconst(leftreg, 1));\n    case 4:\n      return (cgshlconst(leftreg, 2));\n    case 8:\n      return (cgshlconst(leftreg, 3));\n    default:\n      // Load a register with the size and\n      // multiply the leftreg by this size\n      rightreg = cgloadint(n->a_size, P_INT);\n      return (cgmul(leftreg, rightreg));\n    }\n  case A_POSTINC:\n  case A_POSTDEC:\n    // Load and decrement the variable's value into a register\n    // and post increment/decrement it\n    return (cgloadvar(n->sym, n->op));\n  case A_PREINC:\n  case A_PREDEC:\n    // Load and decrement the variable's value into a register\n    // and pre increment/decrement it\n    return (cgloadvar(n->left->sym, n->op));\n  case A_NEGATE:\n    return (cgnegate(leftreg));\n  case A_INVERT:\n    return (cginvert(leftreg));\n  case A_LOGNOT:\n    return (cglognot(leftreg));\n  case A_TOBOOL:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, set the register\n    // to 0 or 1 based on it's zeroeness or non-zeroeness\n    return (cgboolean(leftreg, parentASTop, iflabel));\n  case A_BREAK:\n    cgjump(loopendlabel);\n    return (NOREG);\n  case A_CONTINUE:\n    cgjump(looptoplabel);\n    return (NOREG);\n  case A_CAST:\n    return (leftreg);\t\t// Not much to do\n  default:\n    fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble(char *filename) {\n  cgpreamble(filename);\n}\nvoid genpostamble() {\n  cgpostamble();\n}\nvoid genfreeregs(int keepreg) {\n  cgfreeallregs(keepreg);\n}\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\n\n// Generate a global string.\n// If append is true, append to\n// previous genglobstr() call.\nint genglobstr(char *strvalue, int append) {\n  int l = genlabel();\n  cgglobstr(l, strvalue, append);\n  return (l);\n}\nvoid genglobstrend(void) {\n  cgglobstrend();\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "62_Cleanup/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\nint toupper(int c);\nint tolower(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "62_Cleanup/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n\nint * __errno_location(void);\n\n#define errno (* __errno_location())\n\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "62_Cleanup/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "62_Cleanup/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "62_Cleanup/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n#ifndef EOF\n# define EOF (-1)\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint sprintf(char *str, char *format);\nint snprintf(char *str, size_t size, char *format);\nint fgetc(FILE *stream);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\nFILE *popen(char *command, char *type);\nint pclose(FILE *stream);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "62_Cleanup/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\nint system(char *command);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "62_Cleanup/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\nint strcmp(char *s1, char *s2);\nint strncmp(char *s1, char *s2, size_t n);\nchar *strerror(int errnum);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "62_Cleanup/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "62_Cleanup/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix;\n  posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .s\n  Outfilename = alter_suffix(filename, 's');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Linestart = 1;\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token = 0;\t\t// and set there is no lookahead token\n  genpreamble(filename);\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n\n  // Dump the symbol table if requested\n  if (O_dumpsym) {\n    printf(\"Symbols for %s\\n\", filename);\n    dumpsymtables();\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n\n  // Build the assembly command and run it\n#ifdef __NASM__\n  char *incfilename = alter_suffix(filename, 'n');\n  if (incfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n//  sprintf(cmd, \"%s %s -p%s %s\", ASCMD, outfilename, incfilename, filename);\n  sprintf(cmd, \"%s %s %s\", ASCMD, outfilename, filename);\n#else\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n#endif\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char **objlist) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcSTM] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -M dump the symbol table for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char **argv) {\n  char *outfilename = AOUT;\n  char *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, j, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_dumpsym = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'M':\n\t  O_dumpsym = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    asmfile = do_compile(argv[i]);\t// Compile the source file\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm)\t\t// Remove the assembly file if\n      unlink(asmfile);\t\t// we don't need to keep it\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "62_Cleanup/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "62_Cleanup/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "62_Cleanup/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  int i;\n  for (i = 0; s[i] != '\\0'; i++)\n    if (s[i] == (char) c)\n      return (i);\n  return (-1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t\t// Read from input file\n\n  while (Linestart && c == '#') {\t// We've hit a pre-processor statement\n    Linestart = 0;\t\t\t// No longer at the start of the line\n    scan(&Token);\t\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n'); // Skip to the end of the line\n    c = fgetc(Infile);\t\t\t// and get the next character\n    Linestart = 1;\t\t\t// Now back at the start of the line\n  }\n\n  Linestart = 0;\t\t\t// No longer at the start of the line\n  if ('\\n' == c) {\n    Line++;\t\t\t\t// Increment line count\n    Linestart = 1;\t\t\t// Now back at the start of the line\n  }\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n\n  // We hit a non-hex character, put it back\n  putback(c);\n\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n\n  return (n);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn (hexchar());\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = (char)c;\n  }\n\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = (char)c;\n    }\n    c = next();\n  }\n\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\", \"%=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \"<\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"%\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case '%':\n      if ((c = next()) == '=') {\n\tt->token = T_ASMOD;\n      } else {\n\tputback(c);\n\tt->token = T_MOD;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "62_Cleanup/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, NULL, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, NULL, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, NULL, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree= NULL;\n\n  // Ensure we have 'return'\n  match(T_RETURN, \"return\");\n\n  // See if we have a return value\n  if (Token.token == T_LPAREN) {\n    // Can't return a value if function returns P_VOID\n    if (Functionid->type == P_VOID)\n      fatal(\"Can't return from a void function\");\n\n    // Skip the left parenthesis\n    lparen();\n\n    // Parse the following expression\n    tree = binexpr(0);\n\n    // Ensure this is compatible with the function's type\n    tree = modify_type(tree, Functionid->type, Functionid->ctype, 0);\n    if (tree == NULL)\n      fatal(\"Incompatible type to return\");\n\n    // Get the ')'\n    rparen();\n  }\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, NULL, tree, NULL, 0);\n\n  // Get the ';'\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, P_NONE, NULL, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, P_NONE, NULL, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *body, *n, *c;\n  struct ASTnode *casetree = NULL, *casetail;\n  int inloop = 1, casecount = 0;\n  int seendefault = 0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left = binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n = mkastunary(A_SWITCH, P_NONE, NULL, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch (Token.token) {\n\t// Leave the loop when we hit a '}'\n      case T_RBRACE:\n\tif (casecount == 0)\n\t  fatal(\"No cases in switch\");\n\tinloop = 0;\n\tbreak;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token == T_DEFAULT) {\n\t  ASTop = A_DEFAULT;\n\t  seendefault = 1;\n\t  scan(&Token);\n\t} else {\n\t  ASTop = A_CASE;\n\t  scan(&Token);\n\t  left = binexpr(0);\n\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue = left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n\t  // that there isn't a duplicate case value\n\t  for (c = casetree; c != NULL; c = c->right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n\t}\n\n\t// Scan the ':' and increment the casecount\n\tmatch(T_COLON, \":\");\n\tcasecount++;\n\n\t// If the next token is a T_CASE, the existing case will fall\n\t// into the next case. Otherwise, parse the case body.\n\tif (Token.token == T_CASE)\n\t  body = NULL;\n\telse\n\t  body = compound_statement(1);\n\n\t// Build a sub-tree with any compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree == NULL) {\n\t  casetree = casetail =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t} else {\n\t  casetail->right =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t  casetail = casetail->right;\n\t}\n\tbreak;\n      default:\n\tfatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue = casecount;\n  n->right = casetree;\n  rbrace();\n\n  return (n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n  int linenum= Line;\n\n  switch (Token.token) {\n    case T_SEMI:\n      // An empty statement\n      semi();\n      break;\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      stmt->linenum= linenum;\n      rbrace();\n      return (stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt = binexpr(0);\n        stmt->linenum= linenum;\n\tsemi();\n\treturn (stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      stmt= if_statement(); stmt->linenum= linenum; return(stmt);\n    case T_WHILE:\n      stmt= while_statement(); stmt->linenum= linenum; return(stmt);\n    case T_FOR:\n      stmt= for_statement(); stmt->linenum= linenum; return(stmt);\n    case T_RETURN:\n      stmt= return_statement(); stmt->linenum= linenum; return(stmt);\n    case T_BREAK:\n      stmt= break_statement(); stmt->linenum= linenum; return(stmt);\n    case T_CONTINUE:\n      stmt= continue_statement(); stmt->linenum= linenum; return(stmt);\n    case T_SWITCH:\n      stmt= switch_statement(); stmt->linenum= linenum; return(stmt);\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt = binexpr(0);\n      stmt->linenum= linenum;\n      semi();\n      return (stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Leave if we've hit the end token. We do this first to allow\n    // an empty compound statement\n    if (Token.token == T_RBRACE)\n      return (left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT))\n      return (left);\n\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, NULL, left, NULL, tree, NULL, 0);\n    }\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n"
  },
  {
    "path": "62_Cleanup/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  #ifdef __NASM__\n  node->extinit = 0;\n  #endif\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list,\n\t\t\t\t      int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class == 0 || class == list->class)\n\treturn (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead = Globtail = NULL;\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Membhead = Membtail = NULL;\n  Structhead = Structtail = NULL;\n  Unionhead = Uniontail = NULL;\n  Enumhead = Enumtail = NULL;\n  Typehead = Typetail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev = NULL;\n\n  // Walk the global table looking for static entries\n  for (g = Globhead; g != NULL; g = g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL)\n\tprev->next = g->next;\n      else\n\tGlobhead->next = g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n\tif (prev != NULL)\n\t  Globtail = prev;\n\telse\n\t  Globtail = Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev = g;\n}\n\n// Dump a single symbol\nstatic void dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n    case P_VOID:\n      printf(\"void \");\n      break;\n    case P_CHAR:\n      printf(\"char \");\n      break;\n    case P_INT:\n      printf(\"int \");\n      break;\n    case P_LONG:\n      printf(\"long \");\n      break;\n    case P_STRUCT:\n      if (sym->ctype != NULL)\n\tprintf(\"struct %s \", sym->ctype->name);\n      else\n\tprintf(\"struct %s \", sym->name);\n      break;\n    case P_UNION:\n      if (sym->ctype != NULL)\n\tprintf(\"union %s \", sym->ctype->name);\n      else\n\tprintf(\"union %s \", sym->name);\n      break;\n    default:\n      printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++)\n    printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      break;\n    case S_FUNCTION:\n      printf(\"()\");\n      break;\n    case S_ARRAY:\n      printf(\"[]\");\n      break;\n    default:\n      printf(\" unknown stype\");\n  }\n\n  switch (sym->class) {\n    case C_GLOBAL:\n      printf(\": global\");\n      break;\n    case C_LOCAL:\n      printf(\": local\");\n      break;\n    case C_PARAM:\n      printf(\": param\");\n      break;\n    case C_EXTERN:\n      printf(\": extern\");\n      break;\n    case C_STATIC:\n      printf(\": static\");\n      break;\n    case C_STRUCT:\n      printf(\": struct\");\n      break;\n    case C_UNION:\n      printf(\": union\");\n      break;\n    case C_MEMBER:\n      printf(\": member\");\n      break;\n    case C_ENUMTYPE:\n      printf(\": enumtype\");\n      break;\n    case C_ENUMVAL:\n      printf(\": enumval\");\n      break;\n    case C_TYPEDEF:\n      printf(\": typedef\");\n      break;\n    default:\n      printf(\": unknown class\");\n  }\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      if (sym->class == C_ENUMVAL)\n\tprintf(\", value %d\\n\", sym->st_posn);\n      else\n\tprintf(\", size %d\\n\", sym->size);\n      break;\n    case S_FUNCTION:\n      printf(\", %d params\\n\", sym->nelems);\n      break;\n    case S_ARRAY:\n      printf(\", %d elems, size %d\\n\", sym->nelems, sym->size);\n      break;\n  }\n\n  switch (sym->type & (~0xf)) {\n    case P_STRUCT:\n    case P_UNION:\n      dumptable(sym->member, NULL, 4);\n  }\n\n  switch (sym->stype) {\n    case S_FUNCTION:\n      dumptable(sym->member, NULL, 4);\n  }\n}\n\n// Dump one symbol table\nvoid dumptable(struct symtable *head, char *name, int indent) {\n  struct symtable *sym;\n\n  if (head != NULL && name != NULL)\n    printf(\"%s\\n--------\\n\", name);\n  for (sym = head; sym != NULL; sym = sym->next)\n    dumpsym(sym, indent);\n}\n\nvoid dumpsymtables(void) {\n  dumptable(Globhead, \"Global\", 0);\n  printf(\"\\n\");\n  dumptable(Enumhead, \"Enums\", 0);\n  printf(\"\\n\");\n  dumptable(Typehead, \"Typedefs\", 0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input032.c",
    "content": "Unknown variable or function:pizza on line 4 of input032.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input042.c",
    "content": "Unknown variable or function:fred on line 3 of input042.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input043.c",
    "content": "Unknown variable or function:b on line 3 of input043.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input044.c",
    "content": "Unknown variable or function:z on line 3 of input044.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input046.c",
    "content": "* operator must be followed by an expression of pointer type on line 3 of input046.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input059.c",
    "content": "Unknown variable or function:y on line 3 of input059.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input060.c",
    "content": "Expression is not a struct/union on line 3 of input060.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input061.c",
    "content": "Expression is not a pointer to a struct/union on line 3 of input061.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input086.c",
    "content": "Function definition not at global level on line 2 of input086.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input093.c",
    "content": "Unknown variable or function:fred on line 1 of input093.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input124.c",
    "content": "Cannot ++ on rvalue on line 6 of input124.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input126.c",
    "content": "Unknown variable or function:ptr on line 7 of input126.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input129.c",
    "content": "Cannot ++ and/or -- more than once on line 6 of input129.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input141.c",
    "content": "Declaration of array parameters is not implemented on line 4 of input141.c\n"
  },
  {
    "path": "62_Cleanup/tests/err.input142.c",
    "content": "Array must have non-zero elements:fred on line 1 of input142.c\n"
  },
  {
    "path": "62_Cleanup/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n  printf(\"%d\\n\", 12345);\n  return(3);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "62_Cleanup/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "62_Cleanup/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "62_Cleanup/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "62_Cleanup/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "62_Cleanup/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "62_Cleanup/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "62_Cleanup/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "62_Cleanup/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "62_Cleanup/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "62_Cleanup/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "62_Cleanup/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "62_Cleanup/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "62_Cleanup/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "62_Cleanup/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "62_Cleanup/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "62_Cleanup/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "62_Cleanup/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "62_Cleanup/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "62_Cleanup/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "62_Cleanup/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "62_Cleanup/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "62_Cleanup/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "62_Cleanup/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "62_Cleanup/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "62_Cleanup/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "62_Cleanup/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "62_Cleanup/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "62_Cleanup/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "62_Cleanup/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "62_Cleanup/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input122.c",
    "content": "#include <stdio.h>\n\nint x, y, z1, z2;\n\nint main() {\n  for (x= 0; x <= 1; x++) {\n    for (y= 0; y <= 1; y++) {\n      z1= x || y; z2= x && y;\n      printf(\"x %d, y %d, x || y %d, x && y %d\\n\", x, y, z1, z2);\n    }\n  }\n  \n  //z= x || y;\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input123.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  for (x=0; x < 20; x++)\n    switch(x) {\n      case 2:\n      case 3:\n      case 5:\n      case 7:\n      case 11: printf(\"%2d infant prime\\n\", x); break;\n      case 13:\n      case 17:\n      case 19: printf(\"%2d teen   prime\\n\", x); break;\n      case 0:\n      case 1:\n      case 4:\n      case 6:\n      case 8:\n      case 9:\n      case 10:\n      case 12: printf(\"%2d infant composite\\n\", x); break;\n      default: printf(\"%2d teen   composite\\n\", x); break;\n    }\n\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input124.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary++;\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input125.c",
    "content": "#include <stdio.h>\n\nint ary[5];\nint *ptr;\nint x;\n\nint main() {\n  ary[3]= 2008;\n  ptr= ary;\t\t\t// Load ary's address into ptr\n  x= ary[3]; printf(\"%d\\n\", x);\n  x= ptr[3]; printf(\"%d\\n\", x); // Treat ptr as an array\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input126.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary[3]= 2008;\n  ptr= &ary;\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input127.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nvoid fred(int *ptr) {\t\t// Receive a pointer\n  printf(\"%d\\n\", ptr[3]);\n}\n\nint main() {\n  ary[3]= 2008;\n  printf(\"%d\\n\", ary[3]);\n  fred(ary);\t\t\t// Pass ary as a pointer\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input128.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int val;\n  struct foo *next;\n};\n\nstruct foo head, mid, tail;\n\nint main() {\n  struct foo *ptr;\n  tail.val= 20; tail.next= NULL;\n  mid.val= 15; mid.next= &tail;\n  head.val= 10; head.next= &mid;\n\n  ptr= &head;\n  printf(\"%d %d\\n\", head.val, ptr->val);\n  printf(\"%d %d\\n\", mid.val, ptr->next->val);\n  printf(\"%d %d\\n\", tail.val, ptr->next->next->val);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input129.c",
    "content": "#include <stdio.h>\n\nint x= 6;\n\nint main() {\n  printf(\"%d\\n\", x++ ++);\n  return(0);\n}\n\n"
  },
  {
    "path": "62_Cleanup/tests/input130.c",
    "content": "#include <stdio.h>\n\nchar *x= \"foo\";\n\nint main() {\n  printf(\"Hello \" \"world\" \"\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input131.c",
    "content": "#include <stdio.h>\n\nvoid donothing() { }\n\nint main() {\n  int x=0;\n  printf(\"Doing nothing... \"); donothing();\n  printf(\"nothing done\\n\");\n\n  while (++x < 100) ;\n  printf(\"x is now %d\\n\", x);\n\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input132.c",
    "content": "extern int fred;\nint fred;\n\nint mary;\nextern int mary;\n\nint main() { return(0); }\n"
  },
  {
    "path": "62_Cleanup/tests/input133.c",
    "content": "#include <stdio.h>\n\nextern int fred[];\nint fred[23];\n\nchar mary[100];\nextern char mary[];\n\nvoid main() { printf(\"OK\\n\"); }\n"
  },
  {
    "path": "62_Cleanup/tests/input134.c",
    "content": "#include <stdio.h>\n\nchar y = 'a';\nchar *x;\n\nint main() {\n  x= &y;        if (x && y == 'a') printf(\"1st match\\n\");\n  x= NULL;      if (x && y == 'a') printf(\"2nd match\\n\");\n  x= &y; y='b'; if (x && y == 'a') printf(\"3rd match\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input135.c",
    "content": "#include <stdio.h>\n\nvoid fred() {\n  int x= 5;\n  printf(\"testing x\\n\");\n  if (x > 4) return;\n  printf(\"x below 5\\n\");\n}\n\nint main() {\n  fred();\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input136.c",
    "content": "#include <stdio.h>\n\nint add(int x, int y) {\n  return(x+y);\n}\n\nint main() {\n  int result;\n  result= 3 * add(2,3) - 5 * add(4,6);\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input137.c",
    "content": "#include <stdio.h>\n\nint a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8;\n\nint main() {\n  int x;\n  x= ((((((a + b) + c) + d) + e) + f) + g) + h;\n  x= a + (b + (c + (d + (e + (f + (g + h))))));\n  printf(\"x is %d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input138.c",
    "content": "#include <stdio.h>\n\nint x, y, z;\n\nint a=1;\nint *aptr;\n\nint main() {\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x && y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x || y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // Now some lazy evaluation\n  aptr= NULL;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  aptr= &a;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input139.c",
    "content": "#include <stdio.h>\n\nint same(int x) { return(x); }\n\nint main() {\n  int a= 3;\n\n  if (same(a) && same(a) >= same(a))\n    printf(\"same apparently\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input140.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int  i;\n  int  ary[5];\n  char z;\n\n  // Write below the array\n  z= 'H';\n\n  // Fill the array\n  for (i=0; i < 5; i++)\n    ary[i]= i * i;\n\n  // Write above the array\n  i=14;\n\n  // Print out the array\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", ary[i]);\n\n  // See if either side is OK\n  printf(\"%d %c\\n\", i, z);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input141.c",
    "content": "static int fred[5];\nint jim;\n\nint foo(int mary[6]) { return(5); }\n"
  },
  {
    "path": "62_Cleanup/tests/input142.c",
    "content": "static int fred[];\nint jim;\n"
  },
  {
    "path": "62_Cleanup/tests/input143.c",
    "content": "#include <stdio.h>\n\nchar foo;\nchar *a, *b, *c;\n\nint main() {\n\n  a= b= c= NULL;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  a= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  b= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  c= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  else\n    printf(\"All  three  are non-NULL\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input144.c",
    "content": "#include <stdio.h>\n#include <errno.h>\n#include <string.h>\nchar *filename= \"fred\";\nint main() {\n    fprintf(stdout, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input145.c",
    "content": "#include <stdio.h>\n\nchar *str= \"qwertyuiop\";\n\nint list[]= {3, 5, 7, 9, 11, 13, 15};\n\nint *lptr;\n\nint main() {\n  printf(\"%c\\n\", *str);\n  str= str + 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str -= 1; printf(\"%c\\n\", *str);\n\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input146.c",
    "content": "#include <stdio.h>\n\nchar *str= \"qwertyuiop\";\n\nint list[]= {3, 5, 7, 9, 11, 13, 15};\n\nint *lptr;\n\nint main() {\n  printf(\"%c\\n\", *str);\n  str= str + 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str -= 1; printf(\"%c\\n\", *str);\n  str++; printf(\"%c\\n\", *str);\n  str--; printf(\"%c\\n\", *str);\n  ++str; printf(\"%c\\n\", *str);\n  --str; printf(\"%c\\n\\n\", *str);\n\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  lptr++   ; printf(\"%d\\n\", *lptr);\n  lptr--   ; printf(\"%d\\n\", *lptr);\n  ++lptr   ; printf(\"%d\\n\", *lptr);\n  --lptr   ; printf(\"%d\\n\", *lptr);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input147.c",
    "content": "#include <stdio.h>\n\nint a;\n\nint main() {\n  printf(\"%d\\n\", 24 % 9);\n  printf(\"%d\\n\", 31 % 11);\n  a= 24; a %= 9; printf(\"%d\\n\",a);\n  a= 31; a %= 11; printf(\"%d\\n\",a);\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input148.c",
    "content": "#include <stdio.h>\n\nchar *argv[]= { \"unused\", \"-fish\", \"-cat\", \"owl\" };\nint argc= 4;\n\nint main() {\n  int i;\n\n  for (i = 1; i < argc; i++) {\n    printf(\"i is %d\\n\", i);\n    if (*argv[i] != '-') break;\n  }\n\n  while (i < argc) {\n    printf(\"leftover %s\\n\", argv[i]);\n    i++;\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input149.c",
    "content": "#include <stdio.h>\n\nstatic int localOffset=0;\n\nstatic int newlocaloffset(int size) {\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\nint main() {\n  int i, r;\n  for (i=1; i <= 12; i++) {\n    r= newlocaloffset(i);\n    printf(\"%d %d\\n\", i, r);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/input150.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n\nstruct Svalue {\n  char *thing;\n  int vreg;\n  int intval;\n};\n\nstruct IR {\n  int label;\n  int op;\n  struct Svalue dst;\n  struct Svalue src1;\n  struct Svalue src2;\n  int jmplabel;\n};\n\nstruct foo {\n  int a;\n  int b;\n  struct Svalue *c;\n  int d;\n};\n\nstruct IR *fred;\nstruct foo jane;\n\nint main() {\n  fred= (struct IR *)malloc(sizeof(struct IR));\n  fred->label= 1;\n  fred->op= 2;\n  fred->dst.thing= NULL;\n  fred->dst.vreg=3;\n  fred->dst.intval=4;\n  fred->src1.thing= NULL;\n  fred->src1.vreg=5;\n  fred->src1.intval=6;\n  fred->src2.thing= NULL;\n  fred->src2.vreg=7;\n  fred->src2.intval=8;\n  fred->jmplabel= 9;\n\n  printf(\"%d %d %d\\n\",   fred->label, fred->op, fred->dst.vreg);\n  printf(\"%d %d %d\\n\",   fred->dst.intval, fred->src1.vreg, fred->src1.intval);\n  printf(\"%d %d %d\\n\\n\", fred->src2.vreg, fred->src2.intval, fred->jmplabel);\n\n  jane.c= (struct Svalue *)malloc(sizeof(struct Svalue));\n  jane.a= 1; jane.b= 2; jane.d= 4; \n  jane.c->thing= \"fish\";\n  jane.c->vreg= 3;\n  jane.c->intval= 5;\n\n  printf(\"%d %d %d\\n\", jane.a, jane.b, jane.c->vreg);\n  printf(\"%d %d %s\\n\", jane.d, jane.c->intval, jane.c->thing);\n\n  return(0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "62_Cleanup/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "62_Cleanup/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "62_Cleanup/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "62_Cleanup/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "62_Cleanup/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "62_Cleanup/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "62_Cleanup/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "62_Cleanup/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "62_Cleanup/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "62_Cleanup/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "62_Cleanup/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "62_Cleanup/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "62_Cleanup/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "62_Cleanup/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "62_Cleanup/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "62_Cleanup/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "62_Cleanup/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "62_Cleanup/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "62_Cleanup/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "62_Cleanup/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "62_Cleanup/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "62_Cleanup/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "62_Cleanup/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "62_Cleanup/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "62_Cleanup/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "62_Cleanup/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "62_Cleanup/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "62_Cleanup/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "62_Cleanup/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "62_Cleanup/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "62_Cleanup/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "62_Cleanup/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "62_Cleanup/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "62_Cleanup/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "62_Cleanup/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "62_Cleanup/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "62_Cleanup/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "62_Cleanup/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "62_Cleanup/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "62_Cleanup/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "62_Cleanup/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "62_Cleanup/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "62_Cleanup/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "62_Cleanup/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "62_Cleanup/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "62_Cleanup/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "62_Cleanup/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "62_Cleanup/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "62_Cleanup/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "62_Cleanup/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "62_Cleanup/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "62_Cleanup/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "62_Cleanup/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "62_Cleanup/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "62_Cleanup/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "62_Cleanup/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "62_Cleanup/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "62_Cleanup/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "62_Cleanup/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "62_Cleanup/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "62_Cleanup/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "62_Cleanup/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "62_Cleanup/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "62_Cleanup/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "62_Cleanup/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "62_Cleanup/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "62_Cleanup/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "62_Cleanup/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "62_Cleanup/tests/out.input122.c",
    "content": "x 0, y 0, x || y 0, x && y 0\nx 0, y 1, x || y 1, x && y 0\nx 1, y 0, x || y 1, x && y 0\nx 1, y 1, x || y 1, x && y 1\n"
  },
  {
    "path": "62_Cleanup/tests/out.input123.c",
    "content": " 0 infant composite\n 1 infant composite\n 2 infant prime\n 3 infant prime\n 4 infant composite\n 5 infant prime\n 6 infant composite\n 7 infant prime\n 8 infant composite\n 9 infant composite\n10 infant composite\n11 infant prime\n12 infant composite\n13 teen   prime\n14 teen   composite\n15 teen   composite\n16 teen   composite\n17 teen   prime\n18 teen   composite\n19 teen   prime\n"
  },
  {
    "path": "62_Cleanup/tests/out.input125.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "62_Cleanup/tests/out.input127.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "62_Cleanup/tests/out.input128.c",
    "content": "10 10\n15 15\n20 20\n"
  },
  {
    "path": "62_Cleanup/tests/out.input130.c",
    "content": "Hello world\n"
  },
  {
    "path": "62_Cleanup/tests/out.input131.c",
    "content": "Doing nothing... nothing done\nx is now 100\n"
  },
  {
    "path": "62_Cleanup/tests/out.input132.c",
    "content": ""
  },
  {
    "path": "62_Cleanup/tests/out.input133.c",
    "content": "OK\n"
  },
  {
    "path": "62_Cleanup/tests/out.input134.c",
    "content": "1st match\n"
  },
  {
    "path": "62_Cleanup/tests/out.input135.c",
    "content": "testing x\n"
  },
  {
    "path": "62_Cleanup/tests/out.input136.c",
    "content": "-35\n"
  },
  {
    "path": "62_Cleanup/tests/out.input137.c",
    "content": "x is 36\n"
  },
  {
    "path": "62_Cleanup/tests/out.input138.c",
    "content": "0 0 | 0\n0 1 | 0\n1 0 | 0\n1 1 | 1\n0 0 | 0\n0 1 | 1\n1 0 | 1\n1 1 | 1\naptr is NULL or doesn't point at 1\naptr points at 1\n"
  },
  {
    "path": "62_Cleanup/tests/out.input139.c",
    "content": "same apparently\n"
  },
  {
    "path": "62_Cleanup/tests/out.input140.c",
    "content": "0\n1\n4\n9\n16\n5 H\n"
  },
  {
    "path": "62_Cleanup/tests/out.input143.c",
    "content": "One of the three is NULL\nOne of the three is NULL\nOne of the three is NULL\nAll  three  are non-NULL\n"
  },
  {
    "path": "62_Cleanup/tests/out.input144.c",
    "content": "Unable to open fred: Success\n"
  },
  {
    "path": "62_Cleanup/tests/out.input145.c",
    "content": "q\nw\ne\nr\ne\n3\n5\n7\n9\n7\n"
  },
  {
    "path": "62_Cleanup/tests/out.input146.c",
    "content": "q\nw\ne\nr\ne\nr\ne\nr\ne\n\n3\n5\n7\n9\n7\n9\n7\n9\n7\n"
  },
  {
    "path": "62_Cleanup/tests/out.input147.c",
    "content": "6\n9\n6\n9\n"
  },
  {
    "path": "62_Cleanup/tests/out.input148.c",
    "content": "i is 1\ni is 2\ni is 3\nleftover owl\n"
  },
  {
    "path": "62_Cleanup/tests/out.input149.c",
    "content": "1 -4\n2 -8\n3 -12\n4 -16\n5 -21\n6 -27\n7 -34\n8 -42\n9 -51\n10 -61\n11 -72\n12 -84\n"
  },
  {
    "path": "62_Cleanup/tests/out.input150.c",
    "content": "1 2 3\n4 5 6\n7 8 9\n\n1 2 3\n4 5 fish\n"
  },
  {
    "path": "62_Cleanup/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "62_Cleanup/tests/runtests0",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj0 ]\nthen (cd ..; make install; make cwj0)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj0 -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj0 $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "62_Cleanup/tests/runtests0n",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install; make compn0)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo \n   bn=$(echo $i | cut -d. -f1)\n   if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn0 -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn0 $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s ${bn}.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "62_Cleanup/tests/runtestsn",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../compn ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo \n   bn=$(echo $i | cut -d. -f1)\n   if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../compn -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../compn $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.o out.s ${bn}.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "62_Cleanup/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->ctype = ctype;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  n->linenum= 0;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n  int i;\n\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"A_WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      dumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE\n  if (n->op == A_GLUE)\n    level = -2;\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n\n\n  for (i = 0; i < level; i++)\n    fprintf(stdout, \" \");\n  switch (n->op) {\n    case A_GLUE:\n      fprintf(stdout, \"\\n\\n\");\n      return;\n    case A_FUNCTION:\n      fprintf(stdout, \"A_FUNCTION %s\\n\", n->sym->name);\n      return;\n    case A_ADD:\n      fprintf(stdout, \"A_ADD\\n\");\n      return;\n    case A_SUBTRACT:\n      fprintf(stdout, \"A_SUBTRACT\\n\");\n      return;\n    case A_MULTIPLY:\n      fprintf(stdout, \"A_MULTIPLY\\n\");\n      return;\n    case A_DIVIDE:\n      fprintf(stdout, \"A_DIVIDE\\n\");\n      return;\n    case A_EQ:\n      fprintf(stdout, \"A_EQ\\n\");\n      return;\n    case A_NE:\n      fprintf(stdout, \"A_NE\\n\");\n      return;\n    case A_LT:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GT:\n      fprintf(stdout, \"A_GT\\n\");\n      return;\n    case A_LE:\n      fprintf(stdout, \"A_LE\\n\");\n      return;\n    case A_GE:\n      fprintf(stdout, \"A_GE\\n\");\n      return;\n    case A_INTLIT:\n      fprintf(stdout, \"A_INTLIT %d\\n\", n->a_intvalue);\n      return;\n    case A_STRLIT:\n      fprintf(stdout, \"A_STRLIT rval label L%d\\n\", n->a_intvalue);\n      return;\n    case A_IDENT:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_IDENT rval %s\\n\", n->sym->name);\n      else\n\tfprintf(stdout, \"A_IDENT %s\\n\", n->sym->name);\n      return;\n    case A_ASSIGN:\n      fprintf(stdout, \"A_ASSIGN\\n\");\n      return;\n    case A_WIDEN:\n      fprintf(stdout, \"A_WIDEN\\n\");\n      return;\n    case A_RETURN:\n      fprintf(stdout, \"A_RETURN\\n\");\n      return;\n    case A_FUNCCALL:\n      fprintf(stdout, \"A_FUNCCALL %s\\n\", n->sym->name);\n      return;\n    case A_ADDR:\n      fprintf(stdout, \"A_ADDR %s\\n\", n->sym->name);\n      return;\n    case A_DEREF:\n      if (n->rvalue)\n\tfprintf(stdout, \"A_DEREF rval\\n\");\n      else\n\tfprintf(stdout, \"A_DEREF\\n\");\n      return;\n    case A_SCALE:\n      fprintf(stdout, \"A_SCALE %d\\n\", n->a_size);\n      return;\n    case A_PREINC:\n      fprintf(stdout, \"A_PREINC %s\\n\", n->sym->name);\n      return;\n    case A_PREDEC:\n      fprintf(stdout, \"A_PREDEC %s\\n\", n->sym->name);\n      return;\n    case A_POSTINC:\n      fprintf(stdout, \"A_POSTINC\\n\");\n      return;\n    case A_POSTDEC:\n      fprintf(stdout, \"A_POSTDEC\\n\");\n      return;\n    case A_NEGATE:\n      fprintf(stdout, \"A_NEGATE\\n\");\n      return;\n    case A_BREAK:\n      fprintf(stdout, \"A_BREAK\\n\");\n      return;\n    case A_CONTINUE:\n      fprintf(stdout, \"A_CONTINUE\\n\");\n      return;\n    case A_CASE:\n      fprintf(stdout, \"A_CASE %d\\n\", n->a_intvalue);\n      return;\n    case A_DEFAULT:\n      fprintf(stdout, \"A_DEFAULT\\n\");\n      return;\n    case A_SWITCH:\n      fprintf(stdout, \"A_SWITCH\\n\");\n      return;\n    case A_CAST:\n      fprintf(stdout, \"A_CAST %d\\n\", n->type);\n      return;\n    case A_ASPLUS:\n      fprintf(stdout, \"A_ASPLUS\\n\");\n      return;\n    case A_ASMINUS:\n      fprintf(stdout, \"A_ASMINUS\\n\");\n      return;\n    case A_ASSTAR:\n      fprintf(stdout, \"A_ASSTAR\\n\");\n      return;\n    case A_ASSLASH:\n      fprintf(stdout, \"A_ASSLASH\\n\");\n      return;\n    case A_TOBOOL:\n      fprintf(stdout, \"A_TOBOOL\\n\");\n      return;\n    case A_LOGOR:\n      fprintf(stdout, \"A_LOGOR\\n\");\n      return;\n    case A_LOGAND:\n      fprintf(stdout, \"A_LOGAND\\n\");\n      return;\n    case A_AND:\n      fprintf(stdout, \"A_AND\\n\");\n      return;\n    case A_ASMOD:\n      fprintf(stdout, \"A_ASMOD\\n\");\n      return;\n    case A_INVERT:\n      fprintf(stdout, \"A_INVERT\\n\");\n      return;\n    case A_LOGNOT:\n      fprintf(stdout, \"A_LOGNOT\\n\");\n      return;\n    case A_LSHIFT:\n      fprintf(stdout, \"A_LSHIFT\\n\");\n      return;\n    case A_MOD:\n      fprintf(stdout, \"A_MOD\\n\");\n      return;\n    case A_OR:\n      fprintf(stdout, \"A_OR\\n\");\n      return;\n    case A_RSHIFT:\n      fprintf(stdout, \"A_RSHIFT\\n\");\n      return;\n    case A_TERNARY:\n      fprintf(stdout, \"A_TERNARY\\n\");\n      return;\n    case A_XOR:\n      fprintf(stdout, \"A_XOR\\n\");\n      return;\n    default:\n      fatald(\"Unknown dumpAST operator\", n->op);\n  }\n}\n"
  },
  {
    "path": "62_Cleanup/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n\t\t\t    struct symtable *rctype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // For A_LOGOR and A_LOGAND, both types have to be int or pointer types\n  if (op==A_LOGOR || op==A_LOGAND) {\n    if (!inttype(ltype) && !ptrtype(ltype))\n      return(NULL);\n    if (!inttype(ltype) && !ptrtype(rtype))\n      return(NULL);\n    return (tree);\n  }\n\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // The tree's type size is too big and we can't narrow\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, NULL, tree, NULL, 0));\n  }\n\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return (tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n\n  // We can scale only on add and subtract operations\n  if (op == A_ADD || op == A_SUBTRACT ||\n      op == A_ASPLUS || op == A_ASMINUS) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, rctype, tree, NULL, rsize));\n      else\n\treturn (tree);\t\t// Size 1, no need to scale\n    }\n  }\n\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "63_QBE/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary\nINCDIR=/tmp/include\nBINDIR=/tmp\n\nHSRCS= data.h decl.h defs.h incdir.h\nSRCS= cg.c decl.c expr.c gen.c main.c misc.c \\\n\topt.c scan.c stmt.c sym.c tree.c types.c\n\ncwj: $(SRCS) $(HSRCS)\n\tcc -o cwj -g -Wall $(SRCS)\n\nincdir.h:\n\techo \"#define INCDIR \\\"$(INCDIR)\\\"\" > incdir.h\n\ninstall: cwj\n\tmkdir -p $(INCDIR)\n\trsync -a include/. $(INCDIR)\n\tcp cwj $(BINDIR)\n\tchmod +x $(BINDIR)/cwj\n\nclean:\n\trm -f cwj cwj[0-9] *.o *.s *.q out a.out incdir.h\n\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests)\n\n# Run the tests, stop on the first failure\nstoptest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests stop)\n\n# Run the tests with the\n# compiler that compiled itself\ntest2: install tests/runtests2 cwj2\n\t(cd tests; chmod +x runtests2; ./runtests2)\n\n# Try to do the triple test\ntriple: cwj3\n\tsize cwj[23]\n\n# Paranoid: quadruple test\nquad: cwj4\n\tsize cwj[234]\n\ncwj4: cwj3 $(SRCS) $(HSRCS)\n\t./cwj3 -o cwj4 $(SRCS)\n\ncwj3: cwj2 $(SRCS) $(HSRCS)\n\t./cwj2 -o cwj3 $(SRCS)\n\ncwj2: install $(SRCS) $(HSRCS)\n\t./cwj  -o cwj2 $(SRCS)\n"
  },
  {
    "path": "63_QBE/Readme.md",
    "content": "# Part 63: A QBE Backend\n\nI left the last version of the compiler back at the end of 2019 with a\nplan on working on an improved register allocation scheme. Well, several\nthings got in the road of that, including a personal tragedy in the\nmiddle of 2020.\n\nJust a few weeks ago (in mid-December 2021), I came across a project called\n[QBE](https://c9x.me/compile/) written by Quentin Carbonneaux.\nThis tool describes an intermediate language which is eminently suitable for\na compiler like mine to output. This intermediate language is then translated\ndown to real assembly code. As well, QBE provides and performs:\n\n * An SSA-based intermediate language\n * A linear register allocator with hinting\n * Copy elimination\n * Sparse conditional constant propagation\n * Dead instruction elimination\n * Registerization of small stack slots\n * Split spiller and register allocator thanks to the use of the SSA form\n * Smart spilling heuristic based on loop analysis\n\nEssentially, QBE performs many of the back-end register and code optimisations\nthat a compiler should do. And, given that Quentin has already written the\ncode, I decided to discard my existing x86-64 code generator and write a\ncode generator that outputs the QBE intermediate language.\n\nThe result is this version of the `acwj` compiler. It still passes the\ntriple test. However, the assembly code output using the QBE backend is\nabout half the size as the assembly code output by version 62 of the\ncompiler.\n\nIf you want to try this version of the `acwj` compiler out, then you need\nto download and compile [QBE](https://c9x.me/compile/), and install the\n`qbe` executable somewhere on your $PATH. The `acwj` compiler will output\nintermediate code to a file ending with the `.q` suffix. It then invokes\n`qbe` to translate this to assembly code, and then continues with the\nusual steps to assemble and link this resulting code.\n\nSo, let's begin!\n\n## The QBE Intermediate Language\n\nNow, what I *really* would like to do is to explain to you how QBE\nimplements the\n[static single assignment form](https://en.wikipedia.org/wiki/Static_single_assignment_form), register allocation, dead code elimination etc. However,\nI don't yet have a good grasp of these things myself. Perhaps someone\ncould go through the QBE source code and explain how it works in the way\nthat I've done with the `acwj` compiler.\n\nInstead, I'm going to do a bit of a walk-through on the intermediate\nlanguage that QBE uses and explain how I'm targetting this language\nin `cg.c`, my new code generator.\n\n## Temporary Locations, not Registers\n\nThe QBE intermediate language is an abstract language and not the\nassembly language of a real CPU. Therefore, it doesn't have to have\nthe same limitations such as a fixed set of registers.\n\nInstead, there are an infinite number of *temporary* locations, each\nwith its own name. Temporary locations which are globally visible\nstart with the `$` character, and those which are visible only within\na function start with the `%` character.\n\nTemporary locations do not need to be defined in advance: they can\nbe created on the fly. However, when created, each temporary location\nis defined to have one of several *types*. These types (and their\nsuffixes) are:\n\n * 8-bit bytes (*b*)\n * 16-bit halfwords (*h*)\n * 32-bit words (*w*)\n * 64-bit longs (*l*)\n\nQBE also provides **s**ingle precision floats, **d**ouble precision floats\nand a way to define aggregate types. I don't use these in `acwj`, so I\nwon't discuss them. However, you can read about them in the\n[reference document for QBE's intermediate language](https://c9x.me/compile/doc/il.html).\n\nLocal temporary variables can be created by performing the usual\nactions in an assembly language. Some examples are:\n\n```\n  %b0 =w copy 5              # Create %b0 as a word temporary and\n                             # initialise it with the value 5\n  %fred =w add %c, %d        # Add two temporaries and store in the\n                             # %fred word temporary\n  %p =h call ntohs(h %foo)   # Call ntohs() with the value of the %foo\n                             # temporary and save the halfword result\n                             # in the %p temporary \n```\n\n## Mixing Types\n\nEach temporary has a type. This means that you do have to do some\nconversion between types. For example, you can't do this:\n\n```\n  %x =w copy 5               # int x = 5;\n  %y =l copy %x              # long y = x;\n```\n\nWhen you want to widen a value from a smaller type to a larger type,\nyou need to decide if the smaller type was *signed* or *unsigned*.\nExample:\n\n```\n  %x =w copy -5   # int x = -5;               32-bit value 0xfffffffb\n  %y =l extsw %x  # long y = x;               0xfffffffffffffffb\n  %z =l extuw %x  # long z = (unsigned) x;    0x00000000fffffffb\n```\n\nOn the other hand, you can store a wide value into a smaller temporary\nlocation; QBE simply truncates off the most significant bits.\n\n## Our First Example\n\nSo here is a hand-translation of this C program:\n\n```c\n#include <stdio.h>\n\nint main()\n{\n  int x= 5;\n  long y= x;\n  int z= (int)y;\n  printf(\"%d %ld %d\\n\", x, y, z);\n  return(0);\n}\n```\n\ninto the QBE intermediate language:\n\n```\ndata $L19 = { b \"%d %ld %d\\n\" }\nexport function w $main() {\n@L20\n  %x =w copy 5\n  %y =l extsw %x\n  %z =w copy %y\n  call $printf(l $L19, w %x, l %y, w %z)\n  ret 0\n}\n```\n\nThere are some things which I haven't described yet. The string literal\n`\"%d %ld %d\\n\"` is stored as a sequence of **b**ytes in a global temporary\ncalled `$L19`. Technically, `$L19` is the address of the first byte of\nthe string.\n\n`main()` is defined as a non-local function (hence the `$`) which returns\na 32-bit **w**ord. The `export` keyword indicates that the function is\nvisible outside this file.\n\nThe `@L20` is a label, just like a normal assembly label. QBE requires that\neach function has a starting label.\n\nFinally, the `ret` operation returns from the function. There can only be\none `ret` operation in any function. It must be the last line in the\nfunction, and any value that it is given must match the function's type.\n\n## acwj's QBE Output\n\nNow let's look at how `acwj` compiles the above C program down to the QBE\nintermediate language:\n\n```\nexport function w $main() {\n@L20\n  %.t1 =w copy 5\n  %x =w copy %.t1               # x = 5;\n  %.t2 =w copy %x\n  %.t3 =l extsw %.t2\n  %y =l copy %.t3               # y = x;\n  %.t4 =l copy %y\n  %.t5 =w copy %.t4\n  %z =w copy %.t5               # z = (int) y;\n  %.t6 =w copy %z\n  %.t7 =l copy %y               # Put the arguments into \"registers\"\n  %.t8 =w copy %x\n  %.t9 =l copy $L19             # Call pritnf(), get result back\n  %.t10 =w call $printf(l %.t9, w %.t8, l %.t7, w %.t6, )\n  %.t11 =w copy 0\n  %.ret =w copy %.t11           # Set the return value to 0\n  jmp @L18\n@L18\n  ret %.ret\n}\n```\n\nPretty suboptimal, huh?! `acwj` still believes that variables like `x`\nand `y` live in memory and that \"registers\" have to be used to move\ndata between the variables. I'm using temporary names starting with\n\".t\" so there won't be any conflict with actual C variable names.\n\nThe `return(0)` gets translated into code that copies the value into\nthe `%.ret` temporary and then jumps to the last line in\nthe function. Obviously, that jump is not required here.\n\nSo, overall, the code that `acwj` outputs is pretty inefficient. That's\nwhy I had wanted to add some optimisations to `acwj`. The nice thing, now,\nis that QBE does a great job at dead code elimination and code optimisation.\nHere is the x86-64 translation that QBE performs on the above intermediate\ncode:\n\n```asm\n.text\n.globl main\nmain:\n        pushq %rbp\n        movq %rsp, %rbp                 # Set up the frame & stack pointers\n        movl $5, %ecx                   # Copy 5 into three arguments\n        movl $5, %edx\n        movl $5, %esi\n        leaq L19(%rip), %rdi            # Load the address of the string\n        callq printf                    # Call printf()\n        movl $0, %eax                   # Set the main() return value\n        leave\n        ret                             # and return from main()\n```\n\nLovely. Everything is stored in registers and there's no use of the stack\nfor any of the local variables.\n\n## Locals with Addresses\n\nQBE does a great job of keeping as much data in registers as possible. But\nthere are times when this is not possible. Consider when we need to get the\naddress of a variable, e.g.\n\n```c\nint main()\n{\n  int x= 5;\n  int *p = &x;\n  printf(\"%d %lx\\n\", x, (long)p);\n  return(0);\n}\n```\n\nThe `x` variable definitely needs to be stored in memory so that we can\nobtain the address to store in `p`. To do this, we use the QBE operations\nthat allocate and access memory:\n\n```\nexport function w $main() {\n@L20\n  %x =l alloc8 1                # Allocate 8 bytes for x\n  %.t1 =w copy 5\n  storew %.t1, %x               # Store 5 as a 32-bit value in x\n  %.t2 =l copy %x               # Get the address of x\n  %p =l copy %.t2\n  %.t3 =l copy %p\n  %.t5 =w loadsw %x             # Get the 32-bit value at x\n  %.t6 =l copy $L19\n  %.t7 =w call $printf(l %.t6, w %.t5, l %.t3)\n  %.t8 =w copy 0\n  %.ret =w copy %.t8\n  jmp @L18\n@L18\n  ret %.ret\n}\n```\n\n`%x` is now treated as a pointer to eight bytes on the stack. I chose\nto allocate in groups of eight bytes as this helps to keep\n8-byte longs and pointers correctly aligned. We now need to use the\n`store` and `load` operations to write to and read from the memory\nlocations that `%x` points to.\n\nThe above intermediate code gets translated by QBE to:\n\n```\nmain:\n        pushq %rbp\n        movq %rsp, %rbp\n        subq $16, %rsp                  # Make space on the stack\n        movl $5, -8(%rbp)               # Store 5 on the stack as x\n        leaq -8(%rbp), %rdx             # Get the address of x\n        movl $5, %esi                   # Optimisation: use literal 5\n        leaq L19(%rip), %rdi            # instead of accessing the stack\n        callq printf\n        movl $0, %eax\n        leave\n        ret\n```\n\nAnd that's a pretty optimal translation of `acwj`'s intermediate language!\n\n## QBE and chars\n\nQBE doesn't treat 8-bit bytes or 16-bit halfwords as primary types: there\nare no byte or halfword temporary locations. Instead, these have to be\nstored on the stack or on the heap. So, `acwj` compiles this C code:\n\n```c\nint main()\n{\n  char x= 65;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n```\n\nto:\n\n```\nexport function w $main() {\n@L20\n  %x =l alloc4 1                        # Allocate 4 bytes on the stack\n  %.t1 =w copy 65\n  storew %.t1, %x                       # Store 65 as a 16-bit word\n  %.t2 =w loadub %x                     # Reload it as an 8-bit unsigned byte\n  ...\n}\n```\n\n# Comparisons and Conditional Jumps\n\nQBE has instructions to compare two temporaries and set a third temporary\nto 1 if the comparison is true, 0 otherwise. The instructions are:\n\n * `ceq` for equality\n * `cne` for inequality\n * `csle` for signed lower or equal\n * `cslt` for signed lower\n * `csge` for signed greater or equal\n * `csgt` for signed greater\n * `cule` for unsigned lower or equal\n * `cult` for unsigned lower\n * `cuge` for unsigned greater or equal\n * `cugt` for unsigned greater \n\nfollowed by the type letter of the two arguments. So, the C code:\n\n```c\n  int x= 5;\n  int y= 6;\n  int z= x>y;\n```\n\ncan be compiled down to the intermediate code:\n\n```\n  %x =w copy 5\n  %y =w copy 6\n  %z =w csgtw %x, %y\n```\n\nQBE has only one conditional jump instruction: `jnz`. When the named temporary\nlocation is non-zero, `jnz` jumps to the first label. Otherwise it jumps to\nthe second label. There has to be two labels for `jnz`.\n\nUsing this, we can translate this C code:\n\n```c\n  if (5>6)\n    z= 100;\n  else\n    z= 200;\n```\n\nto:\n\n```\n@L19\n  %.t1 =w csgtw 5, 6            # Compare 5>6, store result in %.t1\n  jnz %.t1, @Ltrue, @Lfalse     # Jump to @Ltrue if true, @Lfalse otherwise\n@Ltrue\n  %z =w copy 100                # Set z to 100 and skip using the\n  jmp @L18                      # absolute jump instruction, jmp\n@Lfalse\n  %z =w copy 200                # Set z to 200\n@L18\n  ...\n```\n\nUsing the comparison instructions and `jnz`, we can implement IF, FOR and\nWHILE constructs.\n\n## Structs and Arrays\n\nThese are pretty straightforward. To access\na field in a struct, take the base address and add on the offset of\nthe field. For arrays elements, we need to scale the\nelement's index by the size of each element. So this C code:\n\n```c\nstruct foo {\n    int field1;\n    int field2;\n} x;\n\nint main() {\n  x.field2= 45;\n  return(0);\n}\n```\n\nis compiled by `acwj` to:\n\n```\nexport data $x = align 8 { l 0 }\nexport function w $main() {\n@L19\n  %.t1 =w copy 45\n  %.t2 =l copy $x               # Get the base address of x\n  %.t3 =l copy 4                \n  %.t2 =l add %.t2, %.t3        # Add 4 to it\n  storew %.t1, %.t2             # Store 45 at this address\n  ...\n}\n```\n\n## Comparing the Old and QBE Code Sizes\n\nQBE provides an easier target for the compiler writer than the\nunderlying machine's assembly code. QBE also optimises the assembly\ncode that it creates from the intermediate language. And QBE\nhas at least two machine targets: x86-64 and ARM-64, which makes the\nfront-end compiler a portable one.\n\nLet's use the old and new `acwj` compilers to compile each C file in\nthe compiler itself. We can then compare the code size in bytes that gets\nproduced by each version:\n\n```\nVersion 62   QBE      File\n-----------------------------\n  18079     6961      cg.o\n  14200     7440      decl.o\n  11735     4815      expr.o\n  10063     4349      gen.o\n   4965     2571      main.o\n   1492      522      misc.o\n   1248      424      opt.o\n   9466     4495      scan.o\n   6531     2888      stmt.o\n   7770     3611      sym.o\n   3617     1711      tree.o\n   2473     1777      types.o\n 106964    44257      Self-compiled cwj binary\n```\n\n## Summary\n\nI'm very glad that I actually targetted a real machine when I wrote\n`acwj` because it forced me to cover such topics as register allocation,\nargument passing to functions, alignment of values etc. But the quality\nof assembly code that `acwj` produced was pretty terrible.\n\nAnd now, I'm glad that I found a way to produce high-quality assembly\noutput by using the\n[QBE intermediate language](https://c9x.me/compile/doc/il.html)\nfor the front-end of the compiler.\n\n## What's Next\n\nI don't know if there's a next after this. The compiler passes all\nthe tests, it compiles itself, and the code that it produces is now\npretty good.\n\nI would like to learn about the concepts that QBE embodies, e.g.\nSSA and register allocation. So, perhaps I'll go off and do some\nresearch and write that up.\n\n[Next step](../64_6809_Target/Readme.md)\n"
  },
  {
    "path": "63_QBE/cg.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Code generator for x86-64 using the QBE intermediate language.\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Switch to the text segment\nvoid cgtextseg() {\n}\n\n// Switch to the data segment\nvoid cgdataseg() {\n}\n\n// Given a scalar type value, return the\n// character that matches the QBE type.\n// Because chars are stored on the stack,\n// we can return 'w' for P_CHAR.\nchar cgqbetype(int type) {\n  if (ptrtype(type))\n    return ('l');\n  switch (type) {\n    case P_VOID:\n      return (' ');\n    case P_CHAR:\n      return ('w');\n    case P_INT:\n      return ('w');\n    case P_LONG:\n      return ('l');\n    default:\n      fatald(\"Bad type in cgqbetype:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type value, return the\n// size of the QBE type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      break;\n    default:\n      // Align whatever we have now on a 4-byte alignment.\n      // I put the generic code here so it can be reused elsewhere.\n      alignment = 4;\n      offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  }\n  return (offset);\n}\n\n// Allocate a QBE temporary\nstatic int nexttemp = 0;\nint cgalloctemp(void) {\n  return (++nexttemp);\n}\n\n// Print out the assembly preamble\n// for one output file\nvoid cgpreamble(char *filename) {\n}\n\n// Nothing to do for the end of a file\nvoid cgpostamble() {\n}\n\n// Boolean flag: has there been a switch statement\n// in this function yet?\nstatic int used_switch;\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int size, bigsize;\n  int label;\n\n  // Output the function's name and return type\n  if (sym->class == C_GLOBAL)\n    fprintf(Outfile, \"export \");\n  fprintf(Outfile, \"function %c $%s(\", cgqbetype(sym->type), name);\n\n  // Output the parameter names and types. For any parameters which\n  // need addresses, change their name as we copy their value below\n  for (parm = sym->member; parm != NULL; parm = parm->next) {\n    if (parm->st_hasaddr == 1)\n      fprintf(Outfile, \"%c %%.p%s, \", cgqbetype(parm->type), parm->name);\n    else\n      fprintf(Outfile, \"%c %%%s, \", cgqbetype(parm->type), parm->name);\n  }\n  fprintf(Outfile, \") {\\n\");\n\n  // Get a label for the function start\n  label = genlabel();\n  cglabel(label);\n\n  // For any parameters which need addresses, allocate memory\n  // on the stack for them. QBE won't let us do alloc1, so\n  // we allocate 4 bytes for chars. Copy the value from the\n  // parameter to the new memory location.\n  // of the parameter\n  for (parm = sym->member; parm != NULL; parm = parm->next) {\n    if (parm->st_hasaddr == 1) {\n      size = cgprimsize(parm->type);\n      bigsize = (size == 1) ? 4 : size;\n      fprintf(Outfile, \"  %%%s =l alloc%d 1\\n\", parm->name, bigsize);\n\n      // Copy to the allocated memory\n      switch (size) {\n\tcase 1:\n\t  fprintf(Outfile, \"  storeb %%.p%s, %%%s\\n\", parm->name, parm->name);\n\t  break;\n\tcase 4:\n\t  fprintf(Outfile, \"  storew %%.p%s, %%%s\\n\", parm->name, parm->name);\n\t  break;\n\tcase 8:\n\t  fprintf(Outfile, \"  storel %%.p%s, %%%s\\n\", parm->name, parm->name);\n      }\n    }\n  }\n\n  // Allocate memory for any local variables that need to be on the\n  // stack. There are two reasons for this. The first is for locals\n  // where their address is used. The second is for char variables\n  // We need to do this as QBE can only truncate down to 8 bits\n  // for locations in memory\n  for (locvar = Loclhead; locvar != NULL; locvar = locvar->next) {\n    if (locvar->st_hasaddr == 1) {\n      // Get the total size for all elements (if an array).\n      // Round up to the nearest multiple of 8, to ensure that\n      // pointers are aligned on 8-byte boundaries\n      size = locvar->size * locvar->nelems;\n      size = (size + 7) >> 3;\n      fprintf(Outfile, \"  %%%s =l alloc8 %d\\n\", locvar->name, size);\n    } else if (locvar->type == P_CHAR) {\n      locvar->st_hasaddr = 1;\n      fprintf(Outfile, \"  %%%s =l alloc4 1\\n\", locvar->name);\n    }\n  }\n\n  used_switch = 0;\t\t// We haven't output the switch handling code yet\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n\n  // Return a value if the function's type isn't void\n  if (sym->type != P_VOID)\n    fprintf(Outfile, \"  ret %%.ret\\n}\\n\");\n  else\n    fprintf(Outfile, \"  ret\\n}\\n\");\n}\n\n// Load an integer literal value into a temporary.\n// Return the number of the temporary.\nint cgloadint(int value, int type) {\n  // Get a new temporary\n  int t = cgalloctemp();\n\n  fprintf(Outfile, \"  %%.t%d =%c copy %d\\n\", t, cgqbetype(type), value);\n  return (t);\n}\n\n// Load a value from a variable into a temporary.\n// Return the number of the temporary. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadvar(struct symtable *sym, int op) {\n  int r, posttemp, offset = 1;\n  char qbeprefix;\n\n  // Get a new temporary\n  r = cgalloctemp();\n\n  // If the symbol is a pointer, use the size\n  // of the type that it points to as any\n  // increment or decrement. If not, it's one.\n  if (ptrtype(sym->type))\n    offset = typesize(value_at(sym->type), sym->ctype);\n\n  // Negate the offset for decrements\n  if (op == A_PREDEC || op == A_POSTDEC)\n    offset = -offset;\n\n  // Get the relevant QBE prefix for the symbol\n  qbeprefix = ((sym->class == C_GLOBAL) || (sym->class == C_STATIC) ||\n\t       (sym->class == C_EXTERN)) ? '$' : '%';\n\n  // If we have a pre-operation\n  if (op == A_PREINC || op == A_PREDEC) {\n    if (sym->st_hasaddr || qbeprefix == '$') {\n      // Get a new temporary\n      posttemp = cgalloctemp();\n      switch (sym->size) {\n\tcase 1:\n\t  fprintf(Outfile, \"  %%.t%d =w loadub %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  fprintf(Outfile, \"  %%.t%d =w add %%.t%d, %d\\n\", posttemp, posttemp,\n\t\t  offset);\n\t  fprintf(Outfile, \"  storeb %%.t%d, %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  break;\n\tcase 4:\n\t  fprintf(Outfile, \"  %%.t%d =w loadsw %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  fprintf(Outfile, \"  %%.t%d =w add %%.t%d, %d\\n\", posttemp, posttemp,\n\t\t  offset);\n\t  fprintf(Outfile, \"  storew %%.t%d, %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  break;\n\tcase 8:\n\t  fprintf(Outfile, \"  %%.t%d =l loadl %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  fprintf(Outfile, \"  %%.t%d =l add %%.t%d, %d\\n\", posttemp, posttemp,\n\t\t  offset);\n\t  fprintf(Outfile, \"  storel %%.t%d, %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n      }\n    } else\n      fprintf(Outfile, \"  %c%s =%c add %c%s, %d\\n\",\n\t      qbeprefix, sym->name, cgqbetype(sym->type), qbeprefix,\n\t      sym->name, offset);\n  }\n  // Now load the output temporary with the value\n  if (sym->st_hasaddr || qbeprefix == '$') {\n    switch (sym->size) {\n      case 1:\n\tfprintf(Outfile, \"  %%.t%d =w loadub %c%s\\n\", r, qbeprefix,\n\t\tsym->name);\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"  %%.t%d =w loadsw %c%s\\n\", r, qbeprefix,\n\t\tsym->name);\n\tbreak;\n      case 8:\n\tfprintf(Outfile, \"  %%.t%d =l loadl %c%s\\n\", r, qbeprefix, sym->name);\n    }\n  } else\n    fprintf(Outfile, \"  %%.t%d =%c copy %c%s\\n\",\n\t    r, cgqbetype(sym->type), qbeprefix, sym->name);\n\n  // If we have a post-operation\n  if (op == A_POSTINC || op == A_POSTDEC) {\n    if (sym->st_hasaddr || qbeprefix == '$') {\n      // Get a new temporary\n      posttemp = cgalloctemp();\n      switch (sym->size) {\n\tcase 1:\n\t  fprintf(Outfile, \"  %%.t%d =w loadub %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  fprintf(Outfile, \"  %%.t%d =w add %%.t%d, %d\\n\", posttemp, posttemp,\n\t\t  offset);\n\t  fprintf(Outfile, \"  storeb %%.t%d, %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  break;\n\tcase 4:\n\t  fprintf(Outfile, \"  %%.t%d =w loadsw %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  fprintf(Outfile, \"  %%.t%d =w add %%.t%d, %d\\n\", posttemp, posttemp,\n\t\t  offset);\n\t  fprintf(Outfile, \"  storew %%.t%d, %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  break;\n\tcase 8:\n\t  fprintf(Outfile, \"  %%.t%d =l loadl %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  fprintf(Outfile, \"  %%.t%d =l add %%.t%d, %d\\n\", posttemp, posttemp,\n\t\t  offset);\n\t  fprintf(Outfile, \"  storel %%.t%d, %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n      }\n    } else\n      fprintf(Outfile, \"  %c%s =%c add %c%s, %d\\n\",\n\t      qbeprefix, sym->name, cgqbetype(sym->type), qbeprefix,\n\t      sym->name, offset);\n  }\n  // Return the temporary with the value\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new temporary\nint cgloadglobstr(int label) {\n  // Get a new temporary\n  int r = cgalloctemp();\n  fprintf(Outfile, \"  %%.t%d =l copy $L%d\\n\", r, label);\n  return (r);\n}\n\n// Add two temporaries together and return\n// the number of the temporary with the result\nint cgadd(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c add %%.t%d, %%.t%d\\n\",\n\t  r1, cgqbetype(type), r1, r2);\n  return (r1);\n}\n\n// Subtract the second temporary from the first and\n// return the number of the temporary with the result\nint cgsub(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c sub %%.t%d, %%.t%d\\n\",\n\t  r1, cgqbetype(type), r1, r2);\n  return (r1);\n}\n\n// Multiply two temporaries together and return\n// the number of the temporary with the result\nint cgmul(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c mul %%.t%d, %%.t%d\\n\",\n\t  r1, cgqbetype(type), r1, r2);\n  return (r1);\n}\n\n// Divide or modulo the first temporary by the second and\n// return the number of the temporary with the result\nint cgdivmod(int r1, int r2, int op, int type) {\n  if (op == A_DIVIDE)\n    fprintf(Outfile, \"  %%.t%d =%c div %%.t%d, %%.t%d\\n\",\n\t    r1, cgqbetype(type), r1, r2);\n  else\n    fprintf(Outfile, \"  %%.t%d =%c rem %%.t%d, %%.t%d\\n\",\n\t    r1, cgqbetype(type), r1, r2);\n  return (r1);\n}\n\n// Bitwise AND two temporaries\nint cgand(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c and %%.t%d, %%.t%d\\n\",\n\t  r1, cgqbetype(type), r1, r2);\n  return (r1);\n}\n\n// Bitwise OR two temporaries\nint cgor(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c or %%.t%d, %%.t%d\\n\",\n\t  r1, cgqbetype(type), r1, r2);\n  return (r1);\n}\n\n// Bitwise XOR two temporaries\nint cgxor(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c xor %%.t%d, %%.t%d\\n\",\n\t  r1, cgqbetype(type), r1, r2);\n  return (r1);\n}\n\n// Shift left r1 by r2 bits\nint cgshl(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c shl %%.t%d, %%.t%d\\n\",\n\t  r1, cgqbetype(type), r1, r2);\n  return (r1);\n}\n\n// Shift right r1 by r2 bits\nint cgshr(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c shr %%.t%d, %%.t%d\\n\",\n\t  r1, cgqbetype(type), r1, r2);\n  return (r1);\n}\n\n// Negate a temporary's value\nint cgnegate(int r, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c sub 0, %%.t%d\\n\", r, cgqbetype(type), r);\n  return (r);\n}\n\n// Invert a temporary's value\nint cginvert(int r, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c xor %%.t%d, -1\\n\", r, cgqbetype(type), r);\n  return (r);\n}\n\n// Logically negate a temporary's value\nint cglognot(int r, int type) {\n  char q = cgqbetype(type);\n  fprintf(Outfile, \"  %%.t%d =%c ceq%c %%.t%d, 0\\n\", r, q, q, r);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given temporary\nvoid cgloadboolean(int r, int val, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c copy %d\\n\", r, cgqbetype(type), val);\n}\n\n// Convert an integer value to a boolean value. Jump if\n// it's an IF, WHILE, LOGAND or LOGOR operation\nint cgboolean(int r, int op, int label, int type) {\n  // Get a label for the next instruction\n  int label2 = genlabel();\n\n  // Get a new temporary for the comparison\n  int r2 = cgalloctemp();\n\n  // Convert temporary to boolean value\n  fprintf(Outfile, \"  %%.t%d =l cne%c %%.t%d, 0\\n\", r2, cgqbetype(type), r);\n\n  switch (op) {\n    case A_IF:\n    case A_WHILE:\n    case A_LOGAND:\n      fprintf(Outfile, \"  jnz %%.t%d, @L%d, @L%d\\n\", r2, label2, label);\n      break;\n    case A_LOGOR:\n      fprintf(Outfile, \"  jnz %%.t%d, @L%d, @L%d\\n\", r2, label, label2);\n      break;\n  }\n\n  // Output the label for the next instruction\n  cglabel(label2);\n  return (r2);\n}\n\n// Call a function with the given symbol id.\n// Return the temprary with the result\nint cgcall(struct symtable *sym, int numargs, int *arglist, int *typelist) {\n  int outr;\n  int i;\n\n  // Get a new temporary for the return result\n  outr = cgalloctemp();\n\n  // Call the function\n  if (sym->type == P_VOID)\n    fprintf(Outfile, \"  call $%s(\", sym->name);\n  else\n    fprintf(Outfile, \"  %%.t%d =%c call $%s(\", outr, cgqbetype(sym->type),\n\t    sym->name);\n\n  // Output the list of arguments\n  for (i = numargs - 1; i >= 0; i--) {\n    fprintf(Outfile, \"%c %%.t%d, \", cgqbetype(typelist[i]), arglist[i]);\n  }\n  fprintf(Outfile, \")\\n\");\n\n  return (outr);\n}\n\n// Shift a temporary left by a constant. As we only\n// use this for address calculations, extend the\n// type to be a QBE 'l' if required\nint cgshlconst(int r, int val, int type) {\n  int r2 = cgalloctemp();\n  int r3 = cgalloctemp();\n\n  if (cgprimsize(type) < 8) {\n    fprintf(Outfile, \"  %%.t%d =l extsw %%.t%d\\n\", r2, r);\n    fprintf(Outfile, \"  %%.t%d =l shl %%.t%d, %d\\n\", r3, r2, val);\n  } else\n    fprintf(Outfile, \"  %%.t%d =l shl %%.t%d, %d\\n\", r3, r, val);\n  return (r3);\n}\n\n// Store a temporary's value into a global variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  // We can store to bytes in memory\n  char q = cgqbetype(sym->type);\n  if (sym->type == P_CHAR)\n    q = 'b';\n\n  fprintf(Outfile, \"  store%c %%.t%d, $%s\\n\", q, r, sym->name);\n  return (r);\n}\n\n// Store a temporary's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  // If the variable is on the stack, use store instructions\n  if (sym->st_hasaddr) {\n    fprintf(Outfile, \"  store%c %%.t%d, %%%s\\n\",\n\t    cgqbetype(sym->type), r, sym->name);\n  } else {\n    fprintf(Outfile, \"  %%%s =%c copy %%.t%d\\n\",\n\t    sym->name, cgqbetype(sym->type), r);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == C_GLOBAL)\n    fprintf(Outfile, \"export \");\n  if ((node->type == P_STRUCT) || (node->type == P_UNION))\n    fprintf(Outfile, \"data $%s = align 8 { \", node->name);\n  else\n    fprintf(Outfile, \"data $%s = align %d { \", node->name, cgprimsize(type));\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n      case 1:\n\tfprintf(Outfile, \"b %d, \", initvalue);\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"w %d, \", initvalue);\n\tbreak;\n      case 8:\n\t// Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n\tif (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t    && initvalue != 0)\n\t  fprintf(Outfile, \"l $L%d, \", initvalue);\n\telse\n\t  fprintf(Outfile, \"l %d, \", initvalue);\n\tbreak;\n      default:\n\tfprintf(Outfile, \"z %d, \", size);\n    }\n  }\n  fprintf(Outfile, \"}\\n\");\n}\n\n// Generate a global string and its label.\n// Don't output the label if append is true.\nvoid cgglobstr(int l, char *strvalue, int append) {\n  char *cptr;\n  if (!append)\n    fprintf(Outfile, \"data $L%d = { \", l);\n\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"b %d, \", *cptr);\n  }\n}\n\n// NUL terminate a global string\nvoid cgglobstrend(void) {\n  fprintf(Outfile, \" b 0 }\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] = { \"ceq\", \"cne\", \"cslt\", \"csgt\", \"csle\", \"csge\" };\n\n// Compare two temporaries and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2, int type) {\n  int r3;\n  char q = cgqbetype(type);\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  // Get a new temporary for the comparison\n  r3 = cgalloctemp();\n\n  fprintf(Outfile, \"  %%.t%d =%c %s%c %%.t%d, %%.t%d\\n\",\n\t  r3, q, cmplist[ASTop - A_EQ], q, r1, r2);\n  return (r3);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"@L%d\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"  jmp @L%d\\n\", l);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"cne\", \"ceq\", \"csge\", \"csle\", \"csgt\", \"cslt\" };\n\n// Compare two temporaries and jump if false.\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label, int type) {\n  int label2;\n  int r3;\n  char q = cgqbetype(type);\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  // Get a label for the next instruction\n  label2 = genlabel();\n\n  // Get a new temporary for the comparison\n  r3 = cgalloctemp();\n\n  fprintf(Outfile, \"  %%.t%d =%c %s%c %%.t%d, %%.t%d\\n\",\n\t  r3, q, invcmplist[ASTop - A_EQ], q, r1, r2);\n  fprintf(Outfile, \"  jnz %%.t%d, @L%d, @L%d\\n\", r3, label, label2);\n  cglabel(label2);\n  return (NOREG);\n}\n\n// Widen the value in the temporary from the old\n// to the new type, and return a temporary with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  char oldq = cgqbetype(oldtype);\n  char newq = cgqbetype(newtype);\n\n  // Get a new temporary\n  int t = cgalloctemp();\n\n  switch (oldtype) {\n    case P_CHAR:\n      fprintf(Outfile, \"  %%.t%d =%c extub %%.t%d\\n\", t, newq, r);\n      break;\n    default:\n      fprintf(Outfile, \"  %%.t%d =%c exts%c %%.t%d\\n\", t, newq, oldq, r);\n  }\n  return (t);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int reg, struct symtable *sym) {\n\n  // Only return a value if we have a value to return\n  if (reg != NOREG)\n    fprintf(Outfile, \"  %%.ret =%c copy %%.t%d\\n\", cgqbetype(sym->type), reg);\n\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier. Return a new temporary\nint cgaddress(struct symtable *sym) {\n  int r = cgalloctemp();\n  char qbeprefix = ((sym->class == C_GLOBAL) || (sym->class == C_STATIC) ||\n\t\t    (sym->class == C_EXTERN)) ? '$' : '%';\n\n  fprintf(Outfile, \"  %%.t%d =l copy %c%s\\n\", r, qbeprefix, sym->name);\n  return (r);\n}\n\n// Dereference a pointer to get the value\n// it points at into a new temporary\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n  // Get temporary for the return result\n  int ret = cgalloctemp();\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"  %%.t%d =w loadub %%.t%d\\n\", ret, r);\n      break;\n    case 4:\n      fprintf(Outfile, \"  %%.t%d =w loadsw %%.t%d\\n\", ret, r);\n      break;\n    case 8:\n      fprintf(Outfile, \"  %%.t%d =l loadl %%.t%d\\n\", ret, r);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (ret);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"  storeb %%.t%d, %%.t%d\\n\", r1, r2);\n      break;\n    case 4:\n      fprintf(Outfile, \"  storew %%.t%d, %%.t%d\\n\", r1, r2);\n      break;\n    case 8:\n      fprintf(Outfile, \"  storel %%.t%d, %%.t%d\\n\", r1, r2);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Move value between temporaries\nvoid cgmove(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c copy %%.t%d\\n\", r2, cgqbetype(type), r1);\n}\n\n// Output a gdb directive to say on which\n// source code line number the following\n// assembly code came from\nvoid cglinenum(int line) {\n  // fprintf(Outfile, \"\\t.loc 1 %d 0\\n\", line);\n}\n\n// Change a temporary value from its old\n// type to a new type.\nint cgcast(int t, int oldtype, int newtype) {\n  // Get temporary for the return result\n  int ret = cgalloctemp();\n  int oldsize, newsize;\n  char qnew;\n\n  // If the new type is a pointer\n  if (ptrtype(newtype)) {\n    // Nothing to do if the old type is also a pointer\n    if (ptrtype(oldtype))\n      return (t);\n    // Otherwise, widen from a primitive type to a pointer\n    return (cgwiden(t, oldtype, newtype));\n  }\n\n  // New type is not a pointer\n  // Get the new QBE type\n  // and the type sizes in bytes\n  qnew = cgqbetype(newtype);\n  oldsize = cgprimsize(oldtype);\n  newsize = cgprimsize(newtype);\n\n  // Nothing to do if the two are the same size\n  if (newsize == oldsize)\n    return (t);\n\n  // If the new size is smaller, we can copy and QBE will truncate it,\n  // otherwise use the QBE cast operation\n  if (newsize < oldsize)\n    fprintf(Outfile, \" %%.t%d =%c copy %%.t%d\\n\", ret, qnew, t);\n  else\n    fprintf(Outfile, \" %%.t%d =%c cast %%.t%d\\n\", ret, qnew, t);\n  return (ret);\n}\n"
  },
  {
    "path": "63_QBE/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Linestart;\t\t     \t// True if at start of a line\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ char *Outfilename;\t\t// Name of file we opened as Outfile\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\nextern char *Tstring[];\t\t\t// List of token strings\n\n// Symbol table lists\nextern_ struct symtable *Globhead, *Globtail;\t  // Global variables and functions\nextern_ struct symtable *Loclhead, *Locltail;\t  // Local variables\nextern_ struct symtable *Parmhead, *Parmtail;\t  // Local parameters\nextern_ struct symtable *Membhead, *Membtail;\t  // Temp list of struct/union members\nextern_ struct symtable *Structhead, *Structtail; // List of struct types\nextern_ struct symtable *Unionhead, *Uniontail;   // List of union types\nextern_ struct symtable *Enumhead,  *Enumtail;    // List of enum types and values\nextern_ struct symtable *Typehead,  *Typetail;    // List of typedefs\n\n// Command-line flags\nextern_ int O_dumpAST;\t\t// If true, dump the AST trees\nextern_ int O_dumpsym;\t\t// If true, dump the symbol table\nextern_ int O_keepasm;\t\t// If true, keep any assembly files\nextern_ int O_assemble;\t\t// If true, assemble the assembly files\nextern_ int O_dolink;\t\t// If true, link the object files\nextern_ int O_verbose;\t\t// If true, print info on compilation stages\n"
  },
  {
    "path": "63_QBE/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type = 0, exstatic = 1;\n\n  // See if the class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == C_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == C_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == C_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = C_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Token.tokstr);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(struct symtable **ctype) {\n  int type = 0, class = 0;\n\n  // Get the type inside the parentheses\n  type = parse_stars(parse_type(ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return (type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree = optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type = tree->type;\n    tree = tree->left;\n  }\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // If the type is char * and\n  if (type == pointer_to(P_CHAR)) {\n    // We have a string literal, return the label number\n    if (tree->op == A_STRLIT)\n      return (tree->a_intvalue);\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue == 0)\n      return (0);\n  }\n  // We only get here with an integer literal. The input type\n  // is an integer type and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return (tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a pointer to a symbol that may already exist\n// return true if this symbol doesn't exist. We use\n// this function to convert externs into globals\nstatic int is_new_symbol(struct symtable *sym, int class,\n\t\t\t int type, struct symtable *ctype) {\n\n  // There is no existing symbol, thus is new\n  if (sym == NULL)\n    return (1);\n\n  // global versus extern: if they match that it's not new\n  // and we can convert the class to global\n  if ((sym->class == C_GLOBAL && class == C_EXTERN)\n      || (sym->class == C_EXTERN && class == C_GLOBAL)) {\n\n    // If the types don't match, there's a problem\n    if (type != sym->type)\n      fatals(\"Type mismatch between global/extern\", sym->name);\n\n    // Struct/unions, also compare the ctype\n    if (type >= P_STRUCT && ctype != sym->ctype)\n      fatals(\"Type mismatch between global/extern\", sym->name);\n\n    // If we get to here, the types match, so mark the symbol\n    // as global\n    sym->class = C_GLOBAL;\n    // Return that symbol is not new\n    return (0);\n  }\n  // It must be a duplicate symbol if we get here\n  fatals(\"Duplicate global variable declaration\", sym->name);\n  return (-1);\t\t\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree = NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym = findglob(varname);\n      if (is_new_symbol(sym, class, type, ctype))\n\tsym = addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case C_LOCAL:\n      sym = addlocl(varname, type, ctype, S_VARIABLE, 1);\n      break;\n    case C_PARAM:\n      sym = addparm(varname, type, ctype, S_VARIABLE);\n      break;\n    case C_MEMBER:\n      sym = addmemb(varname, type, ctype, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != C_GLOBAL && class != C_LOCAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == C_GLOBAL || class == C_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist = (int *) malloc(sizeof(int));\n      sym->initlist[0] = parse_literal(type);\n    }\n    if (class == C_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym->ctype, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, varnode->ctype, 0);\n      if (exprnode == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode->ctype, exprnode,\n\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n\n  return (sym);\n}\n\n// Given the type, name and class of an array variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym = NULL;\t// New symbol table entry\n  int nelems = -1;\t\t// Assume the number of elements won't be given\n  int maxelems;\t\t\t// The maximum number of elements in the init list\n  int *initlist;\t\t// The list of initial elements \n  int i = 0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See if we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems = parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case C_STATIC:\n    case C_EXTERN:\n    case C_GLOBAL:\n      // See if this variable is new or already exists\n      sym = findglob(varname);\n      if (is_new_symbol(sym, class, pointer_to(type), ctype))\n\tsym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class, 0, 0);\n      break;\n    case C_LOCAL:\n      // Add the array to the local symbol table. Mark it as having an address\n      sym = addlocl(varname, pointer_to(type), ctype, S_ARRAY, 0);\n      sym->st_hasaddr = 1;\n      break;\n    default:\n      fatal(\"Declaration of array parameters is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != C_GLOBAL && class != C_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems = nelems;\n    else\n      maxelems = TABLE_INCREMENT;\n    initlist = (int *) malloc(maxelems * sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n\tfatal(\"Too many values in initialisation list\");\n\n      initlist[i++] = parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n\tmaxelems += TABLE_INCREMENT;\n\tinitlist = (int *) realloc(initlist, maxelems * sizeof(int));\n      }\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n\tscan(&Token);\n\tbreak;\n      }\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j = i; j < sym->nelems; j++)\n      initlist[j] = 0;\n\n    if (i > nelems)\n      nelems = i;\n    sym->initlist = initlist;\n  }\n  // Set the size of the array and the number of elements\n  // Only externs can have no elements.\n  if (class != C_EXTERN && nelems <= 0)\n    fatals(\"Array must have non-zero elements\", sym->name);\n\n  sym->nelems = nelems;\n  sym->size = sym->nelems * typesize(type, ctype);\n  // Generate any global space\n  if (class == C_GLOBAL || class == C_STATIC)\n    genglobsym(sym);\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n\tparamcnt = 0;\n\tscan(&Token);\n\tbreak;\n      }\n    }\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, C_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    // Ensure the type of this parameter matches the prototype\n    if (protoptr != NULL) {\n      if (type != protoptr->type)\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree, *finalstmt;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel = 0, paramcnt;\n  int linenum = Line;\n\n  // Text has the identifier's name. If this exists and is a\n  // function, get the id. Otherwise, set oldfuncsym to NULL.\n  if ((oldfuncsym = findsymbol(funcname)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // If this is a new function declaration, get a\n  // label-id for the end label, and add the function\n  // to the symbol table,\n  if (oldfuncsym == NULL) {\n    endlabel = genlabel();\n    // Assumption: functions only return scalar types, so NULL below\n    newfuncsym =\n      addglob(funcname, type, NULL, S_FUNCTION, class, 0, endlabel);\n  }\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    newfuncsym->member = Parmhead;\n    oldfuncsym = newfuncsym;\n  }\n  // Clear out the parameter list\n  Parmhead = Parmtail = NULL;\n\n  // If the declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI)\n    return (oldfuncsym);\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ...\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n  }\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, ctype, tree, oldfuncsym, endlabel);\n  tree->linenum = linenum;\n\n  // Do optimisations on the AST tree\n  tree = optimise(tree);\n\n  // Dump the AST tree if requested\n  if (O_dumpAST) {\n    dumpAST(tree, NOLABEL, 0);\n    fprintf(stdout, \"\\n\\n\");\n  }\n  // Generate the assembly code for it\n  genAST(tree, NOLABEL, NOLABEL, NOLABEL, 0);\n\n  // Now free the symbols associated with this function\n  freeloclsyms();\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addstruct(Text);\n  else\n    ctype = addunion(Text);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t = declaration_list(&m, C_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t == -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Attach to the struct type's node\n  rbrace();\n  if (Membhead == NULL)\n    fatals(\"No members in struct\", ctype->name);\n  ctype->member = Membhead;\n  Membhead = Membtail = NULL;\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name = NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n  else\n    // Build an enum type node for this identifier\n    etype = addenum(name, C_ENUMTYPE, 0);\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", Text);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if (Token.token != T_INTLIT)\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addenum(name, C_ENUMVAL, intval++);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have static/extern in a typedef declaration\");\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // It doesn't exist so add it to the typedef list\n  addtypedef(Text, type, *ctype);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the symbol's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    return (function_declaration(varname, type, ctype, class));\n  }\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case C_EXTERN:\n    case C_STATIC:\n    case C_GLOBAL:\n    case C_LOCAL:\n    case C_PARAM:\n      if (findlocl(varname) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n    case C_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET) {\n    sym = array_declaration(varname, type, ctype, class);\n    *tree = NULL;\t\t// Local arrays are not initialised\n  } else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree = NULL;\n  *gluetree = NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != C_GLOBAL && class != C_STATIC)\n\tfatal(\"Function definition not at global level\");\n      return (type);\n    }\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree == NULL)\n      *gluetree = tree;\n    else\n      *gluetree =\n\tmkastnode(A_GLUE, P_NONE, NULL, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Parse one or more global declarations,\n// either variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype = NULL;\n  struct ASTnode *unused;\n\n  // Loop parsing one declaration list until the end of file\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, C_GLOBAL, T_SEMI, T_EOF, &unused);\n\n    // Skip any separating semicolons\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "63_QBE/decl.h",
    "content": "// Function prototypes for all compiler files\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// scan.c\nvoid reject_token(struct token *t);\nint scan(struct token *t);\n\n// tree.c\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue);\nvoid dumpAST(struct ASTnode *n, int label, int level);\n\n// gen.c\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop);\nvoid genpreamble(char *filename);\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue, int append);\nvoid genglobstrend(void);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nvoid genreturn(int reg, int id);\n\n// cg.c\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nvoid cgtextseg();\nvoid cgdataseg();\nint cgalloctemp(void);\nvoid cgfreeallregs(int keepreg);\nvoid cgfreereg(int reg);\nvoid cgspillregs(void);\nvoid cgpreamble(char *filename);\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadvar(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2, int type);\nint cgsub(int r1, int r2, int type);\nint cgmul(int r1, int r2, int type);\nint cgdivmod(int r1, int r2, int op, int type);\nint cgshlconst(int r, int val, int type);\nint cgcall(struct symtable *sym, int numargs, int *arglist, int *typelist);\nvoid cgcopyarg(int r, int argposn);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue, int append);\nvoid cgglobstrend(void);\nint cgcompare_and_set(int ASTop, int r1, int r2, int type);\nint cgcompare_and_jump(int ASTop, int r1, int r2, int label, int type);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int reg, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nint cgnegate(int r, int type);\nint cginvert(int r, int type);\nint cglognot(int r, int type);\nvoid cgloadboolean(int r, int val, int type);\nint cgboolean(int r, int op, int label, int type);\nint cgand(int r1, int r2, int type);\nint cgor(int r1, int r2, int type);\nint cgxor(int r1, int r2, int type);\nint cgshl(int r1, int r2, int type);\nint cgshr(int r1, int r2, int type);\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2, int type);\nvoid cglinenum(int line);\nint cgcast(int t, int oldtype, int newtype);\n\n// expr.c\nstruct ASTnode *expression_list(int endtoken);\nstruct ASTnode *binexpr(int ptp);\n\n// stmt.c\nstruct ASTnode *compound_statement(int inswitch);\n\n// misc.c\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\n\n// sym.c\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node);\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn);\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems);\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype);\nstruct symtable *addstruct(char *name);\nstruct symtable *addunion(char *name);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems);\nstruct symtable *addenum(char *name, int class, int value);\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype);\nstruct symtable *findglob(char *s);\nstruct symtable *findlocl(char *s);\nstruct symtable *findsymbol(char *s);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid clear_symtable(void);\nvoid freeloclsyms(void);\nvoid freestaticsyms(void);\nvoid dumptable(struct symtable *head, char *name, int indent);\nvoid dumpsymtables(void);\n\n// decl.c\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(struct symtable **ctype);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree);\nvoid global_declarations(void);\n\n// types.c\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n\t\t\t    struct symtable *rctype, int op);\n\n// opt.c\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "63_QBE/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n#include \"incdir.h\"\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#define ASCMD \"as -g -o \"\n#define QBECMD \"qbe -o \"\n#define LDCMD \"cc -g -no-pie -o \"\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,\t\t// 1\n  T_ASSTAR, T_ASSLASH, T_ASMOD,\t\t\t// 4\n  T_QUESTION, T_LOGOR, T_LOGAND,\t\t// 7\n  T_OR, T_XOR, T_AMPER,\t\t\t\t// 10\n  T_EQ, T_NE,\t\t\t\t\t// 13\n  T_LT, T_GT, T_LE, T_GE,\t\t\t// 15\n  T_LSHIFT, T_RSHIFT,\t\t\t\t// 19\n  T_PLUS, T_MINUS, T_STAR, T_SLASH, T_MOD,\t// 21\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,\t\t// 26\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,\t\t// 30\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,\t// 34\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,\t\t// 39\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,\t// 43\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,\t// 47\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,\t\t// 51\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,\t// 55\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,\t// 59\n  T_ARROW, T_COLON\t\t\t\t// 63\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR,\t\t\t//  1\n  A_ASSLASH, A_ASMOD, A_TERNARY, A_LOGOR,\t\t\t//  5\n  A_LOGAND, A_OR, A_XOR, A_AND, A_EQ, A_NE, A_LT,\t\t//  9\n  A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\t\t\t\t// 16\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_MOD,\t\t// 21\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\t\t\t\t// 26\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\t\t\t// 30\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\t\t\t\t// 35\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\t\t\t// 39\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\t\t// 43\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\t\t// 48\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// Structural types\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n\n// Storage classes\nenum {\n  C_GLOBAL = 1,\t\t\t// Globally visible symbol\n  C_LOCAL,\t\t\t// Locally visible symbol\n  C_PARAM,\t\t\t// Locally visible function parameter\n  C_EXTERN,\t\t\t// External globally visible symbol\n  C_STATIC,\t\t\t// Static symbol, visible in one file\n  C_STRUCT,\t\t\t// A struct\n  C_UNION,\t\t\t// A union\n  C_MEMBER,\t\t\t// Member of a struct or union\n  C_ENUMTYPE,\t\t\t// A named enumeration type\n  C_ENUMVAL,\t\t\t// A named enumeration value\n  C_TYPEDEF\t\t\t// A named typedef\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Storage class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements\n#define st_endlabel st_posn\t// For functions, the end label\n#define st_hasaddr  st_posn\t// For locals, 1 if any A_ADDR operation\n  int st_posn;\t\t\t// For struct members, the offset of\n    \t\t\t\t// the member from the base of the struct\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in one list\n  struct symtable *member;\t// First member of a function, struct,\n};\t\t\t\t// union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n  int linenum;\t\t\t// Line number from where this node comes\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no temporary to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "63_QBE/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree =\n      mkastnode(A_GLUE, P_NONE, NULL, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findsymbol(Text)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // XXX Check type of each argument against the function's prototype\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree =\n    mkastunary(A_FUNCCALL, funcptr->type, funcptr->ctype, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(struct ASTnode *left) {\n  struct ASTnode *right;\n\n  // Check that the sub-tree is a pointer\n  if (!ptrtype(left->type))\n    fatal(\"Not an array or pointer\");\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, left->ctype, A_ADD);\n\n  // Return an AST tree where the array's base has the offset added to it,\n  // and dereference the element. Still an lvalue at this point.\n  left =\n    mkastnode(A_ADD, left->type, left->ctype, left, NULL, right, NULL, 0);\n  left =\n    mkastunary(A_DEREF, value_at(left->type), left->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(struct ASTnode *left, int withpointer) {\n  struct ASTnode *right;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the left AST tree is a pointer to struct or union\n  if (withpointer && left->type != pointer_to(P_STRUCT)\n      && left->type != pointer_to(P_UNION))\n    fatal(\"Expression is not a pointer to a struct/union\");\n\n  // Or, check that the left AST tree is a struct or union.\n  // If so, change it from an A_IDENT to an A_ADDR so that\n  // we get the base address, not the value at this address.\n  if (!withpointer) {\n    if (left->type == P_STRUCT || left->type == P_UNION)\n      left->op = A_ADDR;\n    else\n      fatal(\"Expression is not a struct/union\");\n  }\n  // Get the details of the composite type\n  typeptr = left->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Build an A_INTLIT node with the offset\n  right = mkastleaf(A_INTLIT, P_LONG, NULL, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left =\n    mkastnode(A_ADD, pointer_to(m->type), m->ctype, left, NULL, right, NULL,\n\t      0);\n  left = mkastunary(A_DEREF, m->type, m->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse a parenthesised expression and\n// return an AST node representing it.\nstatic struct ASTnode *paren_expression(int ptp) {\n  struct ASTnode *n;\n  int type = 0;\n  struct symtable *ctype = NULL;\n\n  // Beginning of a parenthesised expression, skip the '('.\n  scan(&Token);\n\n  // If the token after is a type identifier, this is a cast expression\n  switch (Token.token) {\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      if (findtypedef(Text) == NULL) {\n\tn = binexpr(0);\t\t// ptp is zero as expression inside ( )\n\tbreak;\n      }\n    case T_VOID:\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n      // Get the type inside the parentheses\n      type = parse_cast(&ctype);\n\n      // Skip the closing ')' and then parse the following expression\n      rparen();\n\n    default:\n      n = binexpr(ptp);\t\t// Scan in the expression. We pass in ptp\n      // as the cast doesn't change the\n      // expression's precedence\n  }\n\n  // We now have at least an expression in n, and possibly a non-zero type\n  // in type if there was a cast. Skip the closing ')' if there was no cast.\n  if (type == 0)\n    rparen();\n  else\n    // Otherwise, make a unary AST node for the cast\n    n = mkastunary(A_CAST, type, ctype, n, NULL, 0);\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(int ptp) {\n  struct ASTnode *n;\n  struct symtable *enumptr;\n  struct symtable *varptr;\n  int id;\n  int type = 0;\n  int size, class;\n  struct symtable *ctype;\n\n  switch (Token.token) {\n    case T_STATIC:\n    case T_EXTERN:\n      fatal(\"Compiler doesn't support static or extern local declarations\");\n    case T_SIZEOF:\n      // Skip the T_SIZEOF and ensure we have a left parenthesis\n      scan(&Token);\n      if (Token.token != T_LPAREN)\n\tfatal(\"Left parenthesis expected after sizeof\");\n      scan(&Token);\n\n      // Get the type inside the parentheses\n      type = parse_stars(parse_type(&ctype, &class));\n\n      // Get the type's size\n      size = typesize(type, ctype);\n      rparen();\n\n      // Make a leaf node int literal with the size\n      return (mkastleaf(A_INTLIT, P_INT, NULL, NULL, size));\n\n    case T_INTLIT:\n      // For an INTLIT token, make a leaf AST node for it.\n      // Make it a P_CHAR if it's within the P_CHAR range\n      if (Token.intvalue >= 0 && Token.intvalue < 256)\n\tn = mkastleaf(A_INTLIT, P_CHAR, NULL, NULL, Token.intvalue);\n      else\n\tn = mkastleaf(A_INTLIT, P_INT, NULL, NULL, Token.intvalue);\n      break;\n\n    case T_STRLIT:\n      // For a STRLIT token, generate the assembly for it.\n      id = genglobstr(Text, 0);\n\n      // For successive STRLIT tokens, append their contents\n      // to this one\n      while (1) {\n\tscan(&Peektoken);\n\tif (Peektoken.token != T_STRLIT)\n\t  break;\n\tgenglobstr(Text, 1);\n\tscan(&Token);\t\t// To skip it properly\n      }\n\n      // Now make a leaf AST node for it. id is the string's label.\n      genglobstrend();\n      n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, NULL, id);\n      break;\n\n    case T_IDENT:\n      // If the identifier matches an enum value,\n      // return an A_INTLIT node\n      if ((enumptr = findenumval(Text)) != NULL) {\n\tn = mkastleaf(A_INTLIT, P_INT, NULL, NULL, enumptr->st_posn);\n\tbreak;\n      }\n      // See if this identifier exists as a symbol. For arrays, set rvalue to 1.\n      if ((varptr = findsymbol(Text)) == NULL)\n\tfatals(\"Unknown variable or function\", Text);\n      switch (varptr->stype) {\n\tcase S_VARIABLE:\n\t  n = mkastleaf(A_IDENT, varptr->type, varptr->ctype, varptr, 0);\n\t  break;\n\tcase S_ARRAY:\n\t  n = mkastleaf(A_ADDR, varptr->type, varptr->ctype, varptr, 0);\n\t  n->rvalue = 1;\n\t  break;\n\tcase S_FUNCTION:\n\t  // Function call, see if the next token is a left parenthesis\n\t  scan(&Token);\n\t  if (Token.token != T_LPAREN)\n\t    fatals(\"Function name used without parentheses\", Text);\n\t  return (funccall());\n\tdefault:\n\t  fatals(\"Identifier not a scalar or array variable\", Text);\n      }\n\n      break;\n\n    case T_LPAREN:\n      return (paren_expression(ptp));\n\n    default:\n      fatals(\"Expecting a primary expression, got token\", Token.tokstr);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(int ptp) {\n  struct ASTnode *n;\n\n  // Get the primary expression\n  n = primary(ptp);\n\n  // Loop until there are no more postfix operators\n  while (1) {\n    switch (Token.token) {\n      case T_LBRACKET:\n\t// An array reference\n\tn = array_access(n);\n\tbreak;\n\n      case T_DOT:\n\t// Access into a struct or union\n\tn = member_access(n, 0);\n\tbreak;\n\n      case T_ARROW:\n\t// Pointer access into a struct or union\n\tn = member_access(n, 1);\n\tbreak;\n\n      case T_INC:\n\t// Post-increment: skip over the token\n\tif (n->rvalue == 1)\n\t  fatal(\"Cannot ++ on rvalue\");\n\tscan(&Token);\n\n\t// Can't do it twice\n\tif (n->op == A_POSTINC || n->op == A_POSTDEC)\n\t  fatal(\"Cannot ++ and/or -- more than once\");\n\n\t// and change the AST operation\n\tn->op = A_POSTINC;\n\tbreak;\n\n      case T_DEC:\n\t// Post-decrement: skip over the token\n\tif (n->rvalue == 1)\n\t  fatal(\"Cannot -- on rvalue\");\n\tscan(&Token);\n\n\t// Can't do it twice\n\tif (n->op == A_POSTINC || n->op == A_POSTDEC)\n\t  fatal(\"Cannot ++ and/or -- more than once\");\n\n\t// and change the AST operation\n\tn->op = A_POSTDEC;\n\tbreak;\n\n      default:\n\treturn (n);\n    }\n  }\n\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_MOD)\n    return (tokentype);\n  fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10,\t\t\t// T_ASMINUS, T_ASSTAR,\n  10, 10,\t\t\t// T_ASSLASH, T_ASMOD,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110, 110\t\t\t// T_STAR, T_SLASH, T_MOD\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_MOD)\n    fatals(\"Token with no precedence in op_precedence:\", Tstring[tokentype]);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (prec);\n}\n\n// prefix_expression: postfix_expression\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstatic struct ASTnode *prefix(int ptp) {\n  struct ASTnode *tree = NULL;\n  switch (Token.token) {\n    case T_AMPER:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix(ptp);\n\n      // Ensure that it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"& operator must be followed by an identifier\");\n\n      // Prevent '&' being performed on an array\n      if (tree->sym->stype == S_ARRAY)\n\tfatal(\"& operator cannot be performed on an array\");\n\n      // Now change the operator to A_ADDR and the type to\n      // a pointer to the original type. Mark the identifier\n      // as needing a real memory address\n      tree->op = A_ADDR;\n      tree->type = pointer_to(tree->type);\n      tree->sym->st_hasaddr = 1;\n      break;\n    case T_STAR:\n      // Get the next token and parse it\n      // recursively as a prefix expression.\n      // Make it an rvalue\n      scan(&Token);\n      tree = prefix(ptp);\n      tree->rvalue = 1;\n\n      // Ensure the tree's type is a pointer\n      if (!ptrtype(tree->type))\n\tfatal(\"* operator must be followed by an expression of pointer type\");\n\n      // Prepend an A_DEREF operation to the tree\n      tree =\n\tmkastunary(A_DEREF, value_at(tree->type), tree->ctype, tree, NULL, 0);\n      break;\n    case T_MINUS:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix(ptp);\n\n      // Prepend a A_NEGATE operation to the tree and\n      // make the child an rvalue. Because chars are unsigned,\n      // also widen this if needed to int so that it's signed\n      tree->rvalue = 1;\n      if (tree->type == P_CHAR)\n\ttree->type = P_INT;\n      tree = mkastunary(A_NEGATE, tree->type, tree->ctype, tree, NULL, 0);\n      break;\n    case T_INVERT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix(ptp);\n\n      // Prepend a A_INVERT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_INVERT, tree->type, tree->ctype, tree, NULL, 0);\n      break;\n    case T_LOGNOT:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix(ptp);\n\n      // Prepend a A_LOGNOT operation to the tree and\n      // make the child an rvalue.\n      tree->rvalue = 1;\n      tree = mkastunary(A_LOGNOT, tree->type, tree->ctype, tree, NULL, 0);\n      break;\n    case T_INC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix(ptp);\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"++ operator must be followed by an identifier\");\n\n      // Prepend an A_PREINC operation to the tree\n      tree = mkastunary(A_PREINC, tree->type, tree->ctype, tree, NULL, 0);\n      break;\n    case T_DEC:\n      // Get the next token and parse it\n      // recursively as a prefix expression\n      scan(&Token);\n      tree = prefix(ptp);\n\n      // For now, ensure it's an identifier\n      if (tree->op != A_IDENT)\n\tfatal(\"-- operator must be followed by an identifier\");\n\n      // Prepend an A_PREDEC operation to the tree\n      tree = mkastunary(A_PREDEC, tree->type, tree->ctype, tree, NULL, 0);\n      break;\n    default:\n      tree = postfix(ptp);\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix(ptp);\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n      case A_TERNARY:\n\t// Ensure we have a ':' token, scan in the expression after it\n\tmatch(T_COLON, \":\");\n\tltemp = binexpr(0);\n\n\t// Build and return the AST for this statement. Use the middle\n\t// expression's type as the return type. XXX We should also\n\t// consider the third expression's type.\n\treturn (mkastnode\n\t\t(A_TERNARY, right->type, right->ctype, left, right, ltemp,\n\t\t NULL, 0));\n\n      case A_ASSIGN:\n\t// Assignment\n\t// Make the right tree into an rvalue\n\tright->rvalue = 1;\n\n\t// Ensure the right's type matches the left\n\tright = modify_type(right, left->type, left->ctype, 0);\n\tif (right == NULL)\n\t  fatal(\"Incompatible expression in assignment\");\n\n\t// Make an assignment AST tree. However, switch\n\t// left and right around, so that the right expression's \n\t// code will be generated before the left expression\n\tltemp = left;\n\tleft = right;\n\tright = ltemp;\n\tbreak;\n\n      default:\n\t// We are not doing a ternary or assignment, so both trees should\n\t// be rvalues. Convert both trees into rvalue if they are lvalue trees\n\tleft->rvalue = 1;\n\tright->rvalue = 1;\n\n\t// Ensure the two types are compatible by trying\n\t// to modify each tree to match the other's type.\n\tltemp = modify_type(left, right->type, right->ctype, ASTop);\n\trtemp = modify_type(right, left->type, left->ctype, ASTop);\n\tif (ltemp == NULL && rtemp == NULL)\n\t  fatal(\"Incompatible types in binary expression\");\n\tif (ltemp != NULL)\n\t  left = ltemp;\n\tif (rtemp != NULL)\n\t  right = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left->ctype, left, NULL,\n\t\tright, NULL, 0);\n\n    // Some operators produce an int result regardless of their operands\n    switch (binastop(tokentype)) {\n      case A_LOGOR:\n      case A_LOGAND:\n      case A_EQ:\n      case A_NE:\n      case A_LT:\n      case A_GT:\n      case A_LE:\n      case A_GE:\n\tleft->type = P_INT;\n    }\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "63_QBE/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\nstatic void update_line(struct ASTnode *n) {\n  // Output the line into the assembly if we've\n  // changed the line number in the AST node\n  if (n->linenum != 0 && Line != n->linenum) {\n    Line = n->linenum;\n    cglinenum(Line);\n  }\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend = 0;\n  int r, r2;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (n->right)\n    Lend = genlabel();\n\n  // Generate the condition code\n  r = genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  // Test to see if the condition is true. If not, jump to the false label\n  r2 = cgloadint(1, P_INT);\n  cgcompare_and_jump(A_EQ, r, r2, Lfalse, P_INT);\n\n  // Generate the true compound statement\n  genAST(n->mid, NOLABEL, looptoplabel, loopendlabel, n->op);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (n->right) {\n    // QBE doesn't like two jump instructions in a row, and\n    // a break at the end of a true IF section causes this. The\n    // solution is to insert a label before the IF jump.\n    cglabel(genlabel());\n    cgjump(Lend);\n  }\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (n->right) {\n    genAST(n->right, NOLABEL, NOLABEL, loopendlabel, n->op);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n) {\n  int Lstart, Lend;\n  int r, r2;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code\n  r = genAST(n->left, Lend, Lstart, Lend, n->op);\n  // Test to see if the condition is true. If not, jump to the end label\n  r2 = cgloadint(1, P_INT);\n  cgcompare_and_jump(A_EQ, r, r2, Lend, P_INT);\n\n  // Generate the compound statement for the body\n  genAST(n->right, NOLABEL, Lstart, Lend, n->op);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n) {\n  int *caselabel;\n  int Lend;\n  int Lcode = 0;\n  int i, reg, r2, type;\n  struct ASTnode *c;\n\n  // Create an array for the case labels\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  if (caselabel == NULL)\n    fatal(\"malloc failed in genSWITCH\");\n\n  // Because QBE doesn't yet support jump tables,\n  // we simply evaluate the switch condition and\n  // then do successive comparisons and jumps,\n  // just like we were doing successive if/elses\n\n  // Generate a label for the end of the switch statement.\n  Lend = genlabel();\n\n  // Generate labels for each case. Put the end label in\n  // as the entry after all the cases\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right)\n    caselabel[i] = genlabel();\n  caselabel[i] = Lend;\n\n  // Output the code to calculate the switch condition\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  type = n->left->type;\n\n  // Walk the right-child linked list to\n  // generate the code for each case\n  for (i = 0, c = n->right; c != NULL; i++, c = c->right) {\n\n    // Generate a label for the actual code that the cases will fall down to\n    if (Lcode == 0)\n      Lcode = genlabel();\n\n    // Output the label for this case's test\n    cglabel(caselabel[i]);\n\n    // Do the comparison and jump, but not if it's the default case\n    if (c->op != A_DEFAULT) {\n      // Jump to the next case if the value doesn't match the case value\n      r2 = cgloadint(c->a_intvalue, type);\n      cgcompare_and_jump(A_EQ, reg, r2, caselabel[i + 1], type);\n\n      // Otherwise, jump to the code to handle this case\n      cgjump(Lcode);\n    }\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    // Reset Lcode so we will create a new code label on the next loop.\n    if (c->left) {\n      cglabel(Lcode);\n      genAST(c->left, NOLABEL, NOLABEL, Lend, 0);\n      Lcode = 0;\n    }\n  }\n\n  // Now output the end label.\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for an\n// A_LOGAND or A_LOGOR operation\nstatic int gen_logandor(struct ASTnode *n) {\n  // Generate two labels\n  int Lfalse = genlabel();\n  int Lend = genlabel();\n  int reg;\n  int type;\n\n  // Generate the code for the left expression\n  // followed by the jump to the false label\n  reg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, 0);\n  type = n->left->type;\n  cgboolean(reg, n->op, Lfalse, type);\n\n  // Generate the code for the right expression\n  // followed by the jump to the false label\n  reg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, 0);\n  type = n->right->type;\n  cgboolean(reg, n->op, Lfalse, type);\n\n  // We didn't jump so set the right boolean value\n  if (n->op == A_LOGAND) {\n    cgloadboolean(reg, 1, type);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 0, type);\n  } else {\n    cgloadboolean(reg, 0, type);\n    cgjump(Lend);\n    cglabel(Lfalse);\n    cgloadboolean(reg, 1, type);\n  }\n  cglabel(Lend);\n  return (reg);\n}\n\n// Generate the code to calculate the arguments of a\n// function call, then call the function with these\n// arguments. Return the temoprary that holds\n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree;\n  int i = 0, numargs = 0;\n  int *arglist = NULL;\n  int *typelist = NULL;\n\n  // Determine the actual number of arguments\n  for (gluetree = n->left; gluetree != NULL; gluetree = gluetree->left) {\n    numargs++;\n  }\n\n  // Allocate memory to hold the list of argument temporaries.\n  // We need to walk the list of arguments to determine the size\n  for (i = 0, gluetree = n->left; gluetree != NULL; gluetree = gluetree->left)\n    i++;\n\n  if (i != 0) {\n    arglist = (int *) malloc(i * sizeof(int));\n    if (arglist == NULL)\n      fatal(\"malloc failed in gen_funccall\");\n    typelist = (int *) malloc(i * sizeof(int));\n    if (typelist == NULL)\n      fatal(\"malloc failed in gen_funccall\");\n  }\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the first.\n  // Also cache the type of each expression\n  for (i = 0, gluetree = n->left; gluetree != NULL; gluetree = gluetree->left) {\n    // Calculate the expression's value\n    arglist[i] =\n      genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    typelist[i++] = gluetree->right->type;\n  }\n\n  // Call the function and return its result\n  return (cgcall(n->sym, numargs, arglist, typelist));\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n) {\n  int Lfalse, Lend;\n  int reg, expreg;\n  int r, r2;\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code\n  r = genAST(n->left, Lfalse, NOLABEL, NOLABEL, n->op);\n  // Test to see if the condition is true. If not, jump to the false label\n  r2 = cgloadint(1, P_INT);\n  cgcompare_and_jump(A_EQ, r, r2, Lfalse, P_INT);\n\n  // Get a temporary to hold the result of the two expressions\n  reg = cgalloctemp();\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known temporary.\n  expreg = genAST(n->mid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg, n->mid->type);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known temporary.\n  expreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg, n->right->type);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the temporary id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg = NOREG, rightreg = NOREG;\n  int lefttype = P_VOID, type = P_VOID;\n  struct symtable *leftsym = NULL;\n\n  // Empty tree, do nothing\n  if (n == NULL)\n    return (NOREG);\n\n  // Update the line number in the output\n  update_line(n);\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n    case A_IF:\n      return (genIF(n, looptoplabel, loopendlabel));\n    case A_WHILE:\n      return (genWHILE(n));\n    case A_SWITCH:\n      return (genSWITCH(n));\n    case A_FUNCCALL:\n      return (gen_funccall(n));\n    case A_TERNARY:\n      return (gen_ternary(n));\n    case A_LOGOR:\n      return (gen_logandor(n));\n    case A_LOGAND:\n      return (gen_logandor(n));\n    case A_GLUE:\n      // Do each child statement, and free the\n      // temporaries after each child\n      if (n->left != NULL)\n\tgenAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);\n      if (n->right != NULL)\n\tgenAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);\n      return (NOREG);\n    case A_FUNCTION:\n      // Generate the function's preamble before the code\n      // in the child sub-tree\n      cgfuncpreamble(n->sym);\n      genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n      cgfuncpostamble(n->sym);\n      return (NOREG);\n  }\n\n  // General AST node handling below\n\n  // Get the left and right sub-tree values. Also get the type\n  if (n->left) {\n    lefttype = type = n->left->type;\n    leftsym = n->left->sym;\n    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);\n  }\n  if (n->right) {\n    type = n->right->type;\n    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);\n  }\n\n  switch (n->op) {\n    case A_ADD:\n      return (cgadd(leftreg, rightreg, type));\n    case A_SUBTRACT:\n      return (cgsub(leftreg, rightreg, type));\n    case A_MULTIPLY:\n      return (cgmul(leftreg, rightreg, type));\n    case A_DIVIDE:\n      return (cgdivmod(leftreg, rightreg, A_DIVIDE, type));\n    case A_MOD:\n      return (cgdivmod(leftreg, rightreg, A_MOD, type));\n    case A_AND:\n      return (cgand(leftreg, rightreg, type));\n    case A_OR:\n      return (cgor(leftreg, rightreg, type));\n    case A_XOR:\n      return (cgxor(leftreg, rightreg, type));\n    case A_LSHIFT:\n      return (cgshl(leftreg, rightreg, type));\n    case A_RSHIFT:\n      return (cgshr(leftreg, rightreg, type));\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      return (cgcompare_and_set(n->op, leftreg, rightreg, lefttype));\n    case A_INTLIT:\n      return (cgloadint(n->a_intvalue, n->type));\n    case A_STRLIT:\n      return (cgloadglobstr(n->a_intvalue));\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\treturn (cgloadvar(n->sym, n->op));\n      } else\n\treturn (NOREG);\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASMOD:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the temporary with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n\tcase A_ASPLUS:\n\t  leftreg = cgadd(leftreg, rightreg, type);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASMINUS:\n\t  leftreg = cgsub(leftreg, rightreg, type);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSTAR:\n\t  leftreg = cgmul(leftreg, rightreg, type);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASSLASH:\n\t  leftreg = cgdivmod(leftreg, rightreg, A_DIVIDE, type);\n\t  n->right = n->left;\n\t  break;\n\tcase A_ASMOD:\n\t  leftreg = cgdivmod(leftreg, rightreg, A_MOD, type);\n\t  n->right = n->left;\n\t  break;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (n->right->op) {\n\tcase A_IDENT:\n\t  if (n->right->sym->class == C_GLOBAL ||\n\t      n->right->sym->class == C_EXTERN ||\n\t      n->right->sym->class == C_STATIC)\n\t    return (cgstorglob(leftreg, n->right->sym));\n\t  else\n\t    return (cgstorlocal(leftreg, n->right->sym));\n\tcase A_DEREF:\n\t  return (cgstorderef(leftreg, rightreg, n->right->type));\n\tdefault:\n\t  fatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      return (cgwiden(leftreg, lefttype, n->type));\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      return (NOREG);\n    case A_ADDR:\n      // If we have a symbol, get its address. Otherwise,\n      // the left temporary already has the address because\n      // it's a member access\n      if (n->sym != NULL)\n\treturn (cgaddress(n->sym));\n      else\n\treturn (leftreg);\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\treturn (cgderef(leftreg, lefttype));\n      else\n\treturn (leftreg);\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n\tcase 2:\n\t  return (cgshlconst(leftreg, 1, type));\n\tcase 4:\n\t  return (cgshlconst(leftreg, 2, type));\n\tcase 8:\n\t  return (cgshlconst(leftreg, 3, type));\n\tdefault:\n\t  // Load a temporary with the size and\n\t  // multiply the leftreg by this size\n\t  rightreg = cgloadint(n->a_size, P_INT);\n\t  return (cgmul(leftreg, rightreg, type));\n      }\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a temporary\n      // and post increment/decrement it\n      return (cgloadvar(n->sym, n->op));\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a temporary\n      // and pre increment/decrement it\n      return (cgloadvar(leftsym, n->op));\n    case A_NEGATE:\n      return (cgnegate(leftreg, type));\n    case A_INVERT:\n      return (cginvert(leftreg, type));\n    case A_LOGNOT:\n      return (cglognot(leftreg, type));\n    case A_TOBOOL:\n      // If the parent AST node is an A_IF or A_WHILE, generate\n      // a compare followed by a jump. Otherwise, set the temporary\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      return (cgboolean(leftreg, parentASTop, iflabel, type));\n    case A_BREAK:\n      cgjump(loopendlabel);\n      return (NOREG);\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      return (NOREG);\n    case A_CAST:\n      return (cgcast(leftreg, lefttype, n->type));\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n  }\n  return (NOREG);\t\t// Keep -Wall happy\n}\n\nvoid genpreamble(char *filename) {\n  cgpreamble(filename);\n}\n\nvoid genpostamble() {\n  cgpostamble();\n}\n\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\n\n// Generate a global string.\n// If append is true, append to\n// previous genglobstr() call.\nint genglobstr(char *strvalue, int append) {\n  int l = genlabel();\n  cgglobstr(l, strvalue, append);\n  return (l);\n}\nvoid genglobstrend(void) {\n  cgglobstrend();\n}\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n"
  },
  {
    "path": "63_QBE/include/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\nint toupper(int c);\nint tolower(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "63_QBE/include/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n\nint * __errno_location(void);\n\n#define errno (* __errno_location())\n\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "63_QBE/include/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "63_QBE/include/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "63_QBE/include/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n#ifndef EOF\n# define EOF (-1)\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format);\nint fprintf(FILE *stream, char *format);\nint sprintf(char *str, char *format);\nint snprintf(char *str, size_t size, char *format);\nint fgetc(FILE *stream);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\nFILE *popen(char *command, char *type);\nint pclose(FILE *stream);\nint fflush(FILE *stream);\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "63_QBE/include/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\nint system(char *command);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "63_QBE/include/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\nint strcmp(char *s1, char *s2);\nint strncmp(char *s1, char *s2, size_t n);\nchar *strerror(int errnum);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "63_QBE/include/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "63_QBE/main.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include <errno.h>\n#include <unistd.h>\n\n// Compiler setup and top-level execution\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Given a string with a '.' and at least a 1-character suffix\n// after the '.', change the suffix to be the given character.\n// Return the new string or NULL if the original string could\n// not be modified\nchar *alter_suffix(char *str, char suffix) {\n  char *posn;\n  char *newstr;\n\n  // Clone the string\n  if ((newstr = strdup(str)) == NULL)\n    return (NULL);\n\n  // Find the '.'\n  if ((posn = strrchr(newstr, '.')) == NULL)\n    return (NULL);\n\n  // Ensure there is a suffix\n  posn++;\n  if (*posn == '\\0')\n    return (NULL);\n\n  // Change the suffix and NUL-terminate the string\n  *posn = suffix;\n  posn++;\n  *posn = '\\0';\n  return (newstr);\n}\n\n// Given an input filename, compile that file\n// down to assembly code. Return the new file's name\nstatic char *do_compile(char *filename) {\n  char cmd[TEXTLEN];\n\n  // Change the input file's suffix to .q\n  Outfilename = alter_suffix(filename, 'q');\n  if (Outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .c on the end\\n\", filename);\n    exit(1);\n  }\n  // Generate the pre-processor command\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", CPPCMD, INCDIR, filename);\n\n  // Open up the pre-processor pipe\n  if ((Infile = popen(cmd, \"r\")) == NULL) {\n    fprintf(stderr, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    exit(1);\n  }\n  Infilename = filename;\n\n  // Create the output file\n  if ((Outfile = fopen(Outfilename, \"w\")) == NULL) {\n    fprintf(stderr, \"Unable to create %s: %s\\n\", Outfilename,\n\t    strerror(errno));\n    exit(1);\n  }\n\n  Line = 1;\t\t\t// Reset the scanner\n  Linestart = 1;\n  Putback = '\\n';\n  clear_symtable();\t\t// Clear the symbol table\n  if (O_verbose)\n    printf(\"compiling %s\\n\", filename);\n  scan(&Token);\t\t\t// Get the first token from the input\n  Peektoken.token = 0;\t\t// and set there is no lookahead token\n  genpreamble(filename);\t// Output the preamble\n  global_declarations();\t// Parse the global declarations\n  genpostamble();\t\t// Output the postamble\n  fclose(Outfile);\t\t// Close the output file\n\n  // Dump the symbol table if requested\n  if (O_dumpsym) {\n    printf(\"Symbols for %s\\n\", filename);\n    dumpsymtables();\n    fprintf(stdout, \"\\n\\n\");\n  }\n\n  freestaticsyms();\t\t// Free any static symbols in the file\n  return (Outfilename);\n}\n\n// Given an input filename, run QBE on the file and\n// produce an assembly file. Return the object filename\nchar *do_qbe(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 's');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .qbe on the end\\n\",\n\t    filename);\n    exit(1);\n  }\n  // Build the QBE command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", QBECMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"QBE translation of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given an input filename, assemble that file\n// down to object code. Return the object filename\nchar *do_assemble(char *filename) {\n  char cmd[TEXTLEN];\n  int err;\n\n  char *outfilename = alter_suffix(filename, 'o');\n  if (outfilename == NULL) {\n    fprintf(stderr, \"Error: %s has no suffix, try .s on the end\\n\", filename);\n    exit(1);\n  }\n  // Build the assembly command and run it\n  snprintf(cmd, TEXTLEN, \"%s %s %s\", ASCMD, outfilename, filename);\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Assembly of %s failed\\n\", filename);\n    exit(1);\n  }\n  return (outfilename);\n}\n\n// Given a list of object files and an output filename,\n// link all of the object filenames together.\nvoid do_link(char *outfilename, char **objlist) {\n  int cnt, size = TEXTLEN;\n  char cmd[TEXTLEN], *cptr;\n  int err;\n\n  // Start with the linker command and the output file\n  cptr = cmd;\n  cnt = snprintf(cptr, size, \"%s %s \", LDCMD, outfilename);\n  cptr += cnt;\n  size -= cnt;\n\n  // Now append each object file\n  while (*objlist != NULL) {\n    cnt = snprintf(cptr, size, \"%s \", *objlist);\n    cptr += cnt;\n    size -= cnt;\n    objlist++;\n  }\n\n  if (O_verbose)\n    printf(\"%s\\n\", cmd);\n  err = system(cmd);\n  if (err != 0) {\n    fprintf(stderr, \"Linking failed\\n\");\n    exit(1);\n  }\n}\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcSTM] [-o outfile] file [file ...]\\n\", prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -T dump the AST trees for each input file\\n\");\n  fprintf(stderr, \"       -M dump the symbol table for each input file\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  exit(1);\n}\n\n// Main program: check arguments and print a usage\n// if we don't have an argument. Open up the input\n// file and call scanfile() to scan the tokens in it.\nenum { MAXOBJ = 100 };\nint main(int argc, char **argv) {\n  char *outfilename = AOUT;\n  char *qbefile, *asmfile, *objfile;\n  char *objlist[MAXOBJ];\n  int i, j, objcnt = 0;\n\n  // Initialise our variables\n  O_dumpAST = 0;\n  O_dumpsym = 0;\n  O_keepasm = 0;\n  O_assemble = 0;\n  O_verbose = 0;\n  O_dolink = 1;\n\n  // Scan for command-line options\n  for (i = 1; i < argc; i++) {\n    // No leading '-', stop scanning for options\n    if (*argv[i] != '-')\n      break;\n\n    // For each option in this argument\n    for (j = 1; (*argv[i] == '-') && argv[i][j]; j++) {\n      switch (argv[i][j]) {\n\tcase 'o':\n\t  outfilename = argv[++i];\t// Save & skip to next argument\n\t  break;\n\tcase 'T':\n\t  O_dumpAST = 1;\n\t  break;\n\tcase 'M':\n\t  O_dumpsym = 1;\n\t  break;\n\tcase 'c':\n\t  O_assemble = 1;\n\t  O_keepasm = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'S':\n\t  O_keepasm = 1;\n\t  O_assemble = 0;\n\t  O_dolink = 0;\n\t  break;\n\tcase 'v':\n\t  O_verbose = 1;\n\t  break;\n\tdefault:\n\t  usage(argv[0]);\n      }\n    }\n  }\n\n  // Ensure we have at lease one input file argument\n  if (i >= argc)\n    usage(argv[0]);\n\n  // Work on each input file in turn\n  while (i < argc) {\n    qbefile = do_compile(argv[i]);\t// Compile the source file\n    asmfile = do_qbe(qbefile);\n\n    if (O_dolink || O_assemble) {\n      objfile = do_assemble(asmfile);\t// Assemble it to object forma\n      if (objcnt == (MAXOBJ - 2)) {\n\tfprintf(stderr, \"Too many object files for the compiler to handle\\n\");\n\texit(1);\n      }\n      objlist[objcnt++] = objfile;\t// Add the object file's name\n      objlist[objcnt] = NULL;\t// to the list of object files\n    }\n\n    if (!O_keepasm) {\t\t// Remove the QBE and assembly files\n      unlink(qbefile);\t\t// if we don't need to keep them\n      unlink(asmfile);\n    }\n    i++;\n  }\n\n  // Now link all the object files together\n  if (O_dolink) {\n    do_link(outfilename, objlist);\n\n    // If we don't need to keep the object\n    // files, then remove them\n    if (!O_assemble) {\n      for (i = 0; objlist[i] != NULL; i++)\n\tunlink(objlist[i]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "63_QBE/misc.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include <stdio.h>\n#include <unistd.h>\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifer and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  fclose(Outfile);\n  unlink(Outfilename);\n  exit(1);\n}\n"
  },
  {
    "path": "63_QBE/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Attempt to do constant folding on\n// the AST tree with the root node n\nstatic struct ASTnode *fold(struct ASTnode *n) {\n\n  if (n == NULL)\n    return (NULL);\n\n  // Fold on the left child, then\n  // do the same on the right child\n  n->left = fold(n->left);\n  n->right = fold(n->right);\n\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n  // Return the possibly modified tree\n  return (n);\n}\n\n// Optimise an AST tree by\n// constant folding in all sub-trees\nstruct ASTnode *optimise(struct ASTnode *n) {\n  n = fold(n);\n  return (n);\n}\n"
  },
  {
    "path": "63_QBE/scan.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  int i;\n  for (i = 0; s[i] != '\\0'; i++)\n    if (s[i] == (char) c)\n      return (i);\n  return (-1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (Linestart && c == '#') {\t// We've hit a pre-processor statement\n    Linestart = 0;\t\t// No longer at the start of the line\n    scan(&Token);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename))\t// and not the one we have now\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n      Line = l;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n\n  Linestart = 0;\t\t// No longer at the start of the line\n  if ('\\n' == c) {\n    Line++;\t\t\t// Increment line count\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n\n  // We hit a non-hex character, put it back\n  putback(c);\n\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n\n  return (n);\n}\n\n// Return the next character from a character\n// or string literal\nstatic int scanch(void) {\n  int i, c, c2;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn (hexchar());\n      default:\n\tfatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    if ((c = scanch()) == '\"') {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = (char) c;\n  }\n\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = (char) c;\n    }\n    c = next();\n  }\n\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\"))\n\treturn (T_VOID);\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\", \"%=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \"<\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"%\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\"\n};\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int c, tokentype;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n  // Skip whitespace\n  c = skip();\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case '%':\n      if ((c = next()) == '=') {\n\tt->token = T_ASMOD;\n      } else {\n\tputback(c);\n\tt->token = T_MOD;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      t->token = T_DOT;\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch();\n      t->token = T_INTLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  t->tokstr = Tstring[t->token];\n  return (1);\n}\n"
  },
  {
    "path": "63_QBE/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, NULL, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'.\n  // Force a non-comparison to be boolean\n  // the tree's operation is a comparison.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, NULL, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, NULL, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree = NULL;\n\n  // Ensure we have 'return'\n  match(T_RETURN, \"return\");\n\n  // See if we have a return value\n  if (Token.token == T_LPAREN) {\n    // Can't return a value if function returns P_VOID\n    if (Functionid->type == P_VOID)\n      fatal(\"Can't return from a void function\");\n\n    // Skip the left parenthesis\n    lparen();\n\n    // Parse the following expression\n    tree = binexpr(0);\n\n    // Ensure this is compatible with the function's type\n    tree = modify_type(tree, Functionid->type, Functionid->ctype, 0);\n    if (tree == NULL)\n      fatal(\"Incompatible type to return\");\n\n    // Get the ')'\n    rparen();\n  }\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, NULL, tree, NULL, 0);\n\n  // Get the ';'\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, P_NONE, NULL, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, P_NONE, NULL, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *body, *n, *c;\n  struct ASTnode *casetree = NULL, *casetail = NULL;\n  int inloop = 1, casecount = 0;\n  int seendefault = 0;\n  int ASTop, casevalue = 0;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left = binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // Build an A_SWITCH subtree with the expression as\n  // the child\n  n = mkastunary(A_SWITCH, P_NONE, NULL, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch (Token.token) {\n\t// Leave the loop when we hit a '}'\n      case T_RBRACE:\n\tif (casecount == 0)\n\t  fatal(\"No cases in switch\");\n\tinloop = 0;\n\tbreak;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token == T_DEFAULT) {\n\t  ASTop = A_DEFAULT;\n\t  seendefault = 1;\n\t  scan(&Token);\n\t} else {\n\t  ASTop = A_CASE;\n\t  scan(&Token);\n\t  left = binexpr(0);\n\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue = left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n\t  // that there isn't a duplicate case value\n\t  for (c = casetree; c != NULL; c = c->right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n\t}\n\n\t// Scan the ':' and increment the casecount\n\tmatch(T_COLON, \":\");\n\tcasecount++;\n\n\t// If the next token is a T_CASE, the existing case will fall\n\t// into the next case. Otherwise, parse the case body.\n\tif (Token.token == T_CASE)\n\t  body = NULL;\n\telse\n\t  body = compound_statement(1);\n\n\t// Build a sub-tree with any compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree == NULL) {\n\t  casetree = casetail =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t} else {\n\t  casetail->right =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t  casetail = casetail->right;\n\t}\n\tbreak;\n      default:\n\tfatals(\"Unexpected token in switch\", Token.tokstr);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue = casecount;\n  n->right = casetree;\n  rbrace();\n\n  return (n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n  int linenum = Line;\n\n  switch (Token.token) {\n    case T_SEMI:\n      // An empty statement\n      semi();\n      break;\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      stmt->linenum = linenum;\n      rbrace();\n      return (stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt = binexpr(0);\n\tstmt->linenum = linenum;\n\tsemi();\n\treturn (stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, C_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      stmt = if_statement();\n      stmt->linenum = linenum;\n      return (stmt);\n    case T_WHILE:\n      stmt = while_statement();\n      stmt->linenum = linenum;\n      return (stmt);\n    case T_FOR:\n      stmt = for_statement();\n      stmt->linenum = linenum;\n      return (stmt);\n    case T_RETURN:\n      stmt = return_statement();\n      stmt->linenum = linenum;\n      return (stmt);\n    case T_BREAK:\n      stmt = break_statement();\n      stmt->linenum = linenum;\n      return (stmt);\n    case T_CONTINUE:\n      stmt = continue_statement();\n      stmt->linenum = linenum;\n      return (stmt);\n    case T_SWITCH:\n      stmt = switch_statement();\n      stmt->linenum = linenum;\n      return (stmt);\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt = binexpr(0);\n      stmt->linenum = linenum;\n      semi();\n      return (stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Leave if we've hit the end token. We do this first to allow\n    // an empty compound statement\n    if (Token.token == T_RBRACE)\n      return (left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT))\n      return (left);\n\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else\n\tleft = mkastnode(A_GLUE, P_NONE, NULL, left, NULL, tree, NULL, 0);\n    }\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n"
  },
  {
    "path": "63_QBE/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Symbol table functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Append a node to the singly-linked list pointed to by head or tail\nvoid appendsym(struct symtable **head, struct symtable **tail,\n\t       struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendsym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node;\n    *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// Create a symbol node to be added to a symbol table list.\n// Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node\nstruct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\tint stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  if (name == NULL)\n    node->name = NULL;\n  else\n    node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a symbol to the global symbol list\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, class, nelems, posn);\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Globhead, &Globtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the local symbol list\nstruct symtable *addlocl(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_LOCAL, nelems, 0);\n\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Loclhead, &Locltail, sym);\n  return (sym);\n}\n\n// Add a symbol to the parameter list\nstruct symtable *addparm(char *name, int type, struct symtable *ctype,\n\t\t\t int stype) {\n  struct symtable *sym = newsym(name, type, ctype, stype, C_PARAM, 1, 0);\n  appendsym(&Parmhead, &Parmtail, sym);\n  return (sym);\n}\n\n// Add a symbol to the temporary member list\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int nelems) {\n  struct symtable *sym =\n    newsym(name, type, ctype, stype, C_MEMBER, nelems, 0);\n\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION)\n    sym->size = ctype->size;\n  appendsym(&Membhead, &Membtail, sym);\n  return (sym);\n}\n\n// Add a struct to the struct list\nstruct symtable *addstruct(char *name) {\n  struct symtable *sym = newsym(name, P_STRUCT, NULL, 0, C_STRUCT, 0, 0);\n  appendsym(&Structhead, &Structtail, sym);\n  return (sym);\n}\n\n// Add a struct to the union list\nstruct symtable *addunion(char *name) {\n  struct symtable *sym = newsym(name, P_UNION, NULL, 0, C_UNION, 0, 0);\n  appendsym(&Unionhead, &Uniontail, sym);\n  return (sym);\n}\n\n// Add an enum type or value to the enum list.\n// Class is C_ENUMTYPE or C_ENUMVAL.\n// Use posn to store the int value.\nstruct symtable *addenum(char *name, int class, int value) {\n  struct symtable *sym = newsym(name, P_INT, NULL, 0, class, 0, value);\n  appendsym(&Enumhead, &Enumtail, sym);\n  return (sym);\n}\n\n// Add a typedef to the typedef list\nstruct symtable *addtypedef(char *name, int type, struct symtable *ctype) {\n  struct symtable *sym = newsym(name, type, ctype, 0, C_TYPEDEF, 0, 0);\n  appendsym(&Typehead, &Typetail, sym);\n  return (sym);\n}\n\n// Search for a symbol in a specific list.\n// Return a pointer to the found node or NULL if not found.\n// If class is not zero, also match on the given class\nstatic struct symtable *findsyminlist(char *s, struct symtable *list,\n\t\t\t\t      int class) {\n  for (; list != NULL; list = list->next)\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class == 0 || class == list->class)\n\treturn (list);\n  return (NULL);\n}\n\n// Determine if the symbol s is in the global symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findglob(char *s) {\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Determine if the symbol s is in the local symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  return (findsyminlist(s, Loclhead, 0));\n}\n\n// Determine if the symbol s is in the symbol table.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findsymbol(char *s) {\n  struct symtable *node;\n\n  // Look for a parameter if we are in a function's body\n  if (Functionid) {\n    node = findsyminlist(s, Functionid->member, 0);\n    if (node)\n      return (node);\n  }\n  // Otherwise, try the local and global symbol lists\n  node = findsyminlist(s, Loclhead, 0);\n  if (node)\n    return (node);\n  return (findsyminlist(s, Globhead, 0));\n}\n\n// Find a member in the member list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  return (findsyminlist(s, Membhead, 0));\n}\n\n// Find a struct in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findsyminlist(s, Structhead, 0));\n}\n\n// Find a struct in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findsyminlist(s, Unionhead, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMTYPE));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findsyminlist(s, Enumhead, C_ENUMVAL));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findsyminlist(s, Typehead, 0));\n}\n\n// Reset the contents of the symbol table\nvoid clear_symtable(void) {\n  Globhead = Globtail = NULL;\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Membhead = Membtail = NULL;\n  Structhead = Structtail = NULL;\n  Unionhead = Uniontail = NULL;\n  Enumhead = Enumtail = NULL;\n  Typehead = Typetail = NULL;\n}\n\n// Clear all the entries in the local symbol table\nvoid freeloclsyms(void) {\n  Loclhead = Locltail = NULL;\n  Parmhead = Parmtail = NULL;\n  Functionid = NULL;\n}\n\n// Remove all static symbols from the global symbol table\nvoid freestaticsyms(void) {\n  // g points at current node, prev at the previous one\n  struct symtable *g, *prev = NULL;\n\n  // Walk the global table looking for static entries\n  for (g = Globhead; g != NULL; g = g->next) {\n    if (g->class == C_STATIC) {\n\n      // If there's a previous node, rearrange the prev pointer\n      // to skip over the current node. If not, g is the head,\n      // so do the same to Globhead\n      if (prev != NULL)\n\tprev->next = g->next;\n      else\n\tGlobhead->next = g->next;\n\n      // If g is the tail, point Globtail at the previous node\n      // (if there is one), or Globhead\n      if (g == Globtail) {\n\tif (prev != NULL)\n\t  Globtail = prev;\n\telse\n\t  Globtail = Globhead;\n      }\n    }\n  }\n\n  // Point prev at g before we move up to the next node\n  prev = g;\n}\n\n// Dump a single symbol\nstatic void dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n    case P_VOID:\n      printf(\"void \");\n      break;\n    case P_CHAR:\n      printf(\"char \");\n      break;\n    case P_INT:\n      printf(\"int \");\n      break;\n    case P_LONG:\n      printf(\"long \");\n      break;\n    case P_STRUCT:\n      if (sym->ctype != NULL)\n\tprintf(\"struct %s \", sym->ctype->name);\n      else\n\tprintf(\"struct %s \", sym->name);\n      break;\n    case P_UNION:\n      if (sym->ctype != NULL)\n\tprintf(\"union %s \", sym->ctype->name);\n      else\n\tprintf(\"union %s \", sym->name);\n      break;\n    default:\n      printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++)\n    printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      break;\n    case S_FUNCTION:\n      printf(\"()\");\n      break;\n    case S_ARRAY:\n      printf(\"[]\");\n      break;\n    default:\n      printf(\" unknown stype\");\n  }\n\n  switch (sym->class) {\n    case C_GLOBAL:\n      printf(\": global\");\n      break;\n    case C_LOCAL:\n      printf(\": local\");\n      break;\n    case C_PARAM:\n      printf(\": param\");\n      break;\n    case C_EXTERN:\n      printf(\": extern\");\n      break;\n    case C_STATIC:\n      printf(\": static\");\n      break;\n    case C_STRUCT:\n      printf(\": struct\");\n      break;\n    case C_UNION:\n      printf(\": union\");\n      break;\n    case C_MEMBER:\n      printf(\": member\");\n      break;\n    case C_ENUMTYPE:\n      printf(\": enumtype\");\n      break;\n    case C_ENUMVAL:\n      printf(\": enumval\");\n      break;\n    case C_TYPEDEF:\n      printf(\": typedef\");\n      break;\n    default:\n      printf(\": unknown class\");\n  }\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      if (sym->class == C_ENUMVAL)\n\tprintf(\", value %d\\n\", sym->st_posn);\n      else\n\tprintf(\", size %d\\n\", sym->size);\n      break;\n    case S_FUNCTION:\n      printf(\", %d params\\n\", sym->nelems);\n      break;\n    case S_ARRAY:\n      printf(\", %d elems, size %d\\n\", sym->nelems, sym->size);\n      break;\n  }\n\n  switch (sym->type & (~0xf)) {\n    case P_STRUCT:\n    case P_UNION:\n      dumptable(sym->member, NULL, 4);\n  }\n\n  switch (sym->stype) {\n    case S_FUNCTION:\n      dumptable(sym->member, NULL, 4);\n  }\n}\n\n// Dump one symbol table\nvoid dumptable(struct symtable *head, char *name, int indent) {\n  struct symtable *sym;\n\n  if (head != NULL && name != NULL)\n    printf(\"%s\\n--------\\n\", name);\n  for (sym = head; sym != NULL; sym = sym->next)\n    dumpsym(sym, indent);\n}\n\nvoid dumpsymtables(void) {\n  dumptable(Globhead, \"Global\", 0);\n  printf(\"\\n\");\n  dumptable(Enumhead, \"Enums\", 0);\n  printf(\"\\n\");\n  dumptable(Typehead, \"Typedefs\", 0);\n}\n"
  },
  {
    "path": "63_QBE/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "63_QBE/tests/err.input032.c",
    "content": "Unknown variable or function:pizza on line 4 of input032.c\n"
  },
  {
    "path": "63_QBE/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "63_QBE/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "63_QBE/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "63_QBE/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "63_QBE/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "63_QBE/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "63_QBE/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "63_QBE/tests/err.input040.c",
    "content": "No return for function with non-void type on line 4 of input040.c\n"
  },
  {
    "path": "63_QBE/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "63_QBE/tests/err.input042.c",
    "content": "Unknown variable or function:fred on line 3 of input042.c\n"
  },
  {
    "path": "63_QBE/tests/err.input043.c",
    "content": "Unknown variable or function:b on line 3 of input043.c\n"
  },
  {
    "path": "63_QBE/tests/err.input044.c",
    "content": "Unknown variable or function:z on line 3 of input044.c\n"
  },
  {
    "path": "63_QBE/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "63_QBE/tests/err.input046.c",
    "content": "* operator must be followed by an expression of pointer type on line 3 of input046.c\n"
  },
  {
    "path": "63_QBE/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "63_QBE/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "63_QBE/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "63_QBE/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "63_QBE/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "63_QBE/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "63_QBE/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "63_QBE/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "63_QBE/tests/err.input059.c",
    "content": "Unknown variable or function:y on line 3 of input059.c\n"
  },
  {
    "path": "63_QBE/tests/err.input060.c",
    "content": "Expression is not a struct/union on line 3 of input060.c\n"
  },
  {
    "path": "63_QBE/tests/err.input061.c",
    "content": "Expression is not a pointer to a struct/union on line 3 of input061.c\n"
  },
  {
    "path": "63_QBE/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "63_QBE/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "63_QBE/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "63_QBE/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "63_QBE/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "63_QBE/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "63_QBE/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "63_QBE/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "63_QBE/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "63_QBE/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "63_QBE/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "63_QBE/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "63_QBE/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "63_QBE/tests/err.input086.c",
    "content": "Function definition not at global level on line 2 of input086.c\n"
  },
  {
    "path": "63_QBE/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "63_QBE/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "63_QBE/tests/err.input093.c",
    "content": "Unknown variable or function:fred on line 1 of input093.c\n"
  },
  {
    "path": "63_QBE/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "63_QBE/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "63_QBE/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "63_QBE/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "63_QBE/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "63_QBE/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "63_QBE/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "63_QBE/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "63_QBE/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "63_QBE/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "63_QBE/tests/err.input124.c",
    "content": "Cannot ++ on rvalue on line 6 of input124.c\n"
  },
  {
    "path": "63_QBE/tests/err.input126.c",
    "content": "Unknown variable or function:ptr on line 7 of input126.c\n"
  },
  {
    "path": "63_QBE/tests/err.input129.c",
    "content": "Cannot ++ and/or -- more than once on line 6 of input129.c\n"
  },
  {
    "path": "63_QBE/tests/err.input141.c",
    "content": "Declaration of array parameters is not implemented on line 4 of input141.c\n"
  },
  {
    "path": "63_QBE/tests/err.input142.c",
    "content": "Array must have non-zero elements:fred on line 1 of input142.c\n"
  },
  {
    "path": "63_QBE/tests/input001.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "63_QBE/tests/input002.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "63_QBE/tests/input003.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "63_QBE/tests/input004.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "63_QBE/tests/input005.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "63_QBE/tests/input006.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "63_QBE/tests/input007.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "63_QBE/tests/input008.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "63_QBE/tests/input009.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "63_QBE/tests/input010.c",
    "content": "int printf(char *fmt);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "63_QBE/tests/input011.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%d\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%d\\n\", k); }\n  return(i);\n}\n"
  },
  {
    "path": "63_QBE/tests/input012.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "63_QBE/tests/input013.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "63_QBE/tests/input014.c",
    "content": "int printf(char *fmt);\n\nint fred() {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input015.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input016.c",
    "content": "int printf(char *fmt);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input017.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input018.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input018a.c",
    "content": "int printf(char *fmt);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input019.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input020.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input021.c",
    "content": "int printf(char *fmt);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input022.c",
    "content": "int printf(char *fmt);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%d\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%d\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%d\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%d\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input023.c",
    "content": "int printf(char *fmt);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input024.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input025.c",
    "content": "int printf(char *fmt);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input026.c",
    "content": "int printf(char *fmt);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%d\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input027.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input028.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input029.c",
    "content": "int printf(char *fmt);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input031.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "63_QBE/tests/input032.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "63_QBE/tests/input033.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "63_QBE/tests/input035.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "63_QBE/tests/input036.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "63_QBE/tests/input037.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "63_QBE/tests/input038.c",
    "content": "int printf(char *fmt);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "63_QBE/tests/input039.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; }\n"
  },
  {
    "path": "63_QBE/tests/input040.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= 5; }\n"
  },
  {
    "path": "63_QBE/tests/input041.c",
    "content": "int printf(char *fmt);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "63_QBE/tests/input042.c",
    "content": "int printf(char *fmt);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "63_QBE/tests/input043.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "63_QBE/tests/input044.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "63_QBE/tests/input045.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "63_QBE/tests/input046.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "63_QBE/tests/input047.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "63_QBE/tests/input048.c",
    "content": "int printf(char *fmt);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "63_QBE/tests/input049.c",
    "content": "int printf(char *fmt);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "63_QBE/tests/input050.c",
    "content": "int printf(char *fmt);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "63_QBE/tests/input051.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "63_QBE/tests/input052.c",
    "content": "int printf(char *fmt);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "63_QBE/tests/input053.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input054.c",
    "content": "int printf(char *fmt);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input055.c",
    "content": "int printf(char *fmt);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "63_QBE/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "63_QBE/tests/input058.c",
    "content": "int printf(char *fmt);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%d\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%d\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "63_QBE/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "63_QBE/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "63_QBE/tests/input062.c",
    "content": "int printf(char *fmt);\n\nunion fred {\n  char w;\n  int  x;\n  int  y;\n  long z;\n};\n\nunion fred var1;\nunion fred *varptr;\n\nint main() {\n  var1.x= 65; printf(\"%d\\n\", var1.x);\n  var1.x= 66; printf(\"%d\\n\", var1.x); printf(\"%d\\n\", var1.y);\n  printf(\"The next two depend on the endian of the platform\\n\");\n  printf(\"%d\\n\", var1.w); printf(\"%d\\n\", var1.z);\n\n  varptr= &var1; varptr->x= 67;\n  printf(\"%d\\n\", varptr->x); printf(\"%d\\n\", varptr->y);\n\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input063.c",
    "content": "int printf(char *fmt);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "63_QBE/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "63_QBE/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "63_QBE/tests/input067.c",
    "content": "int printf(char *fmt);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "63_QBE/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "63_QBE/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "63_QBE/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "63_QBE/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "63_QBE/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "63_QBE/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "63_QBE/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "63_QBE/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "63_QBE/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "63_QBE/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "63_QBE/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "63_QBE/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "63_QBE/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "63_QBE/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "63_QBE/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "63_QBE/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "63_QBE/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "63_QBE/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "63_QBE/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "63_QBE/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "63_QBE/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "63_QBE/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input115.c",
    "content": "#include <stdio.h>\nstruct foo { int x; char y; long z; }; \ntypedef struct foo blah;\n\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int type;                     // Primitive type for the symbol\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int stype;                    // Structural type for the symbol\n  int class;                    // Storage class for the symbol\n  int size;                     // Total size in bytes of this symbol\n  int nelems;                   // Functions: # params. Arrays: # elements\n#define st_endlabel st_posn     // For functions, the end label\n  int st_posn;                  // For locals, the negative offset\n                                // from the stack base pointer\n  int *initlist;                // List of initial values\n  struct symtable *next;        // Next symbol in one list\n  struct symtable *member;      // First member of a function, struct,\n};                              // union or enum\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;                       // \"Operation\" to be performed on this tree\n  int type;                     // Type of any expression this tree generates\n  int rvalue;                   // True if the node is an rvalue\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  struct symtable *sym;         // For many AST nodes, the pointer to\n                                // the symbol in the symbol table\n#define a_intvalue a_size       // For A_INTLIT, the integer value\n  int a_size;                   // For A_SCALE, the size to scale by\n};\n\nint main() {\n  printf(\"%ld\\n\", sizeof(char));\n  printf(\"%ld\\n\", sizeof(int));\n  printf(\"%ld\\n\", sizeof(long));\n  printf(\"%ld\\n\", sizeof(char *));\n  printf(\"%ld\\n\", sizeof(blah));\n  printf(\"%ld\\n\", sizeof(struct symtable));\n  printf(\"%ld\\n\", sizeof(struct ASTnode));\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "63_QBE/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input122.c",
    "content": "#include <stdio.h>\n\nint x, y, z1, z2;\n\nint main() {\n  for (x= 0; x <= 1; x++) {\n    for (y= 0; y <= 1; y++) {\n      z1= x || y; z2= x && y;\n      printf(\"x %d, y %d, x || y %d, x && y %d\\n\", x, y, z1, z2);\n    }\n  }\n  \n  //z= x || y;\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input123.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  for (x=0; x < 20; x++)\n    switch(x) {\n      case 2:\n      case 3:\n      case 5:\n      case 7:\n      case 11: printf(\"%2d infant prime\\n\", x); break;\n      case 13:\n      case 17:\n      case 19: printf(\"%2d teen   prime\\n\", x); break;\n      case 0:\n      case 1:\n      case 4:\n      case 6:\n      case 8:\n      case 9:\n      case 10:\n      case 12: printf(\"%2d infant composite\\n\", x); break;\n      default: printf(\"%2d teen   composite\\n\", x); break;\n    }\n\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input124.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary++;\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input125.c",
    "content": "#include <stdio.h>\n\nint ary[5];\nint *ptr;\nint x;\n\nint main() {\n  ary[3]= 2008;\n  ptr= ary;\t\t\t// Load ary's address into ptr\n  x= ary[3]; printf(\"%d\\n\", x);\n  x= ptr[3]; printf(\"%d\\n\", x); // Treat ptr as an array\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input126.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary[3]= 2008;\n  ptr= &ary;\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input127.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nvoid fred(int *ptr) {\t\t// Receive a pointer\n  printf(\"%d\\n\", ptr[3]);\n}\n\nint main() {\n  ary[3]= 2008;\n  printf(\"%d\\n\", ary[3]);\n  fred(ary);\t\t\t// Pass ary as a pointer\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input128.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int val;\n  struct foo *next;\n};\n\nstruct foo head, mid, tail;\n\nint main() {\n  struct foo *ptr;\n  tail.val= 20; tail.next= NULL;\n  mid.val= 15; mid.next= &tail;\n  head.val= 10; head.next= &mid;\n\n  ptr= &head;\n  printf(\"%d %d\\n\", head.val, ptr->val);\n  printf(\"%d %d\\n\", mid.val, ptr->next->val);\n  printf(\"%d %d\\n\", tail.val, ptr->next->next->val);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input129.c",
    "content": "#include <stdio.h>\n\nint x= 6;\n\nint main() {\n  printf(\"%d\\n\", x++ ++);\n  return(0);\n}\n\n"
  },
  {
    "path": "63_QBE/tests/input130.c",
    "content": "#include <stdio.h>\n\nchar *x= \"foo\";\n\nint main() {\n  printf(\"Hello \" \"world\" \"\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input131.c",
    "content": "#include <stdio.h>\n\nvoid donothing() { }\n\nint main() {\n  int x=0;\n  printf(\"Doing nothing... \"); donothing();\n  printf(\"nothing done\\n\");\n\n  while (++x < 100) ;\n  printf(\"x is now %d\\n\", x);\n\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input132.c",
    "content": "extern int fred;\nint fred;\n\nint mary;\nextern int mary;\n\nint main() { return(0); }\n"
  },
  {
    "path": "63_QBE/tests/input133.c",
    "content": "#include <stdio.h>\n\nextern int fred[];\nint fred[23];\n\nchar mary[100];\nextern char mary[];\n\nvoid main() { printf(\"OK\\n\"); }\n"
  },
  {
    "path": "63_QBE/tests/input134.c",
    "content": "#include <stdio.h>\n\nchar y = 'a';\nchar *x;\n\nint main() {\n  x= &y;        if (x && y == 'a') printf(\"1st match\\n\");\n  x= NULL;      if (x && y == 'a') printf(\"2nd match\\n\");\n  x= &y; y='b'; if (x && y == 'a') printf(\"3rd match\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input135.c",
    "content": "#include <stdio.h>\n\nvoid fred() {\n  int x= 5;\n  printf(\"testing x\\n\");\n  if (x > 4) return;\n  printf(\"x below 5\\n\");\n}\n\nint main() {\n  fred();\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input136.c",
    "content": "#include <stdio.h>\n\nint add(int x, int y) {\n  return(x+y);\n}\n\nint main() {\n  int result;\n  result= 3 * add(2,3) - 5 * add(4,6);\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input137.c",
    "content": "#include <stdio.h>\n\nint a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8;\n\nint main() {\n  int x;\n  x= ((((((a + b) + c) + d) + e) + f) + g) + h;\n  x= a + (b + (c + (d + (e + (f + (g + h))))));\n  printf(\"x is %d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input138.c",
    "content": "#include <stdio.h>\n\nint x, y, z;\n\nint a=1;\nint *aptr;\n\nint main() {\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x && y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x || y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // Now some lazy evaluation\n  aptr= NULL;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  aptr= &a;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input139.c",
    "content": "#include <stdio.h>\n\nint same(int x) { return(x); }\n\nint main() {\n  int a= 3;\n\n  if (same(a) && same(a) >= same(a))\n    printf(\"same apparently\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input140.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int  i;\n  int  ary[5];\n  char z;\n\n  // Write below the array\n  z= 'H';\n\n  // Fill the array\n  for (i=0; i < 5; i++)\n    ary[i]= i * i;\n\n  // Write above the array\n  i=14;\n\n  // Print out the array\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", ary[i]);\n\n  // See if either side is OK\n  printf(\"%d %c\\n\", i, z);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input141.c",
    "content": "static int fred[5];\nint jim;\n\nint foo(int mary[6]) { return(5); }\n"
  },
  {
    "path": "63_QBE/tests/input142.c",
    "content": "static int fred[];\nint jim;\n"
  },
  {
    "path": "63_QBE/tests/input143.c",
    "content": "#include <stdio.h>\n\nchar foo;\nchar *a, *b, *c;\n\nint main() {\n\n  a= b= c= NULL;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  a= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  b= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  c= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  else\n    printf(\"All  three  are non-NULL\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input144.c",
    "content": "#include <stdio.h>\n#include <errno.h>\n#include <string.h>\nchar *filename= \"fred\";\nint main() {\n    fprintf(stdout, \"Unable to open %s: %s\\n\", filename, strerror(errno));\n    return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input145.c",
    "content": "#include <stdio.h>\n\nchar *str= \"qwertyuiop\";\n\nint list[]= {3, 5, 7, 9, 11, 13, 15};\n\nint *lptr;\n\nint main() {\n  printf(\"%c\\n\", *str);\n  str= str + 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str -= 1; printf(\"%c\\n\", *str);\n\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input146.c",
    "content": "#include <stdio.h>\n\nchar *str= \"qwertyuiop\";\n\nint list[]= {3, 5, 7, 9, 11, 13, 15};\n\nint *lptr;\n\nint main() {\n  printf(\"%c\\n\", *str);\n  str= str + 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str -= 1; printf(\"%c\\n\", *str);\n  str++; printf(\"%c\\n\", *str);\n  str--; printf(\"%c\\n\", *str);\n  ++str; printf(\"%c\\n\", *str);\n  --str; printf(\"%c\\n\\n\", *str);\n\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  lptr++   ; printf(\"%d\\n\", *lptr);\n  lptr--   ; printf(\"%d\\n\", *lptr);\n  ++lptr   ; printf(\"%d\\n\", *lptr);\n  --lptr   ; printf(\"%d\\n\", *lptr);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input147.c",
    "content": "#include <stdio.h>\n\nint a;\n\nint main() {\n  printf(\"%d\\n\", 24 % 9);\n  printf(\"%d\\n\", 31 % 11);\n  a= 24; a %= 9; printf(\"%d\\n\",a);\n  a= 31; a %= 11; printf(\"%d\\n\",a);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input148.c",
    "content": "#include <stdio.h>\n\nchar *argv[]= { \"unused\", \"-fish\", \"-cat\", \"owl\" };\nint argc= 4;\n\nint main() {\n  int i;\n\n  for (i = 1; i < argc; i++) {\n    printf(\"i is %d\\n\", i);\n    if (*argv[i] != '-') break;\n  }\n\n  while (i < argc) {\n    printf(\"leftover %s\\n\", argv[i]);\n    i++;\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input149.c",
    "content": "#include <stdio.h>\n\nstatic int localOffset=0;\n\nstatic int newlocaloffset(int size) {\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\nint main() {\n  int i, r;\n  for (i=1; i <= 12; i++) {\n    r= newlocaloffset(i);\n    printf(\"%d %d\\n\", i, r);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input150.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n\nstruct Svalue {\n  char *thing;\n  int vreg;\n  int intval;\n};\n\nstruct IR {\n  int label;\n  int op;\n  struct Svalue dst;\n  struct Svalue src1;\n  struct Svalue src2;\n  int jmplabel;\n};\n\nstruct foo {\n  int a;\n  int b;\n  struct Svalue *c;\n  int d;\n};\n\nstruct IR *fred;\nstruct foo jane;\n\nint main() {\n  fred= (struct IR *)malloc(sizeof(struct IR));\n  fred->label= 1;\n  fred->op= 2;\n  fred->dst.thing= NULL;\n  fred->dst.vreg=3;\n  fred->dst.intval=4;\n  fred->src1.thing= NULL;\n  fred->src1.vreg=5;\n  fred->src1.intval=6;\n  fred->src2.thing= NULL;\n  fred->src2.vreg=7;\n  fred->src2.intval=8;\n  fred->jmplabel= 9;\n\n  printf(\"%d %d %d\\n\",   fred->label, fred->op, fred->dst.vreg);\n  printf(\"%d %d %d\\n\",   fred->dst.intval, fred->src1.vreg, fred->src1.intval);\n  printf(\"%d %d %d\\n\\n\", fred->src2.vreg, fred->src2.intval, fred->jmplabel);\n\n  jane.c= (struct Svalue *)malloc(sizeof(struct Svalue));\n  jane.a= 1; jane.b= 2; jane.d= 4; \n  jane.c->thing= \"fish\";\n  jane.c->vreg= 3;\n  jane.c->intval= 5;\n\n  printf(\"%d %d %d\\n\", jane.a, jane.b, jane.c->vreg);\n  printf(\"%d %d %s\\n\", jane.d, jane.c->intval, jane.c->thing);\n\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input151.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input152.c",
    "content": "#include <stdio.h>\n\nvoid fred(int x) {\n  int a = 2;\n  int *b = &x;\n  printf(\"%d %d %d\\n\", x, a, *b);\n}\n\nint main() {\n  fred(4);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input153.c",
    "content": "#include <stdio.h>\n\nenum {\n  C_GLOBAL = 1, C_LOCAL, C_PARAM, C_EXTERN, C_STATIC, C_STRUCT,\n  C_UNION, C_MEMBER, C_ENUMTYPE, C_ENUMVAL, C_TYPEDEF\n};\n\nint main() {\n  int class;\n  int b;\n  char q;\n\n  for (class = C_GLOBAL; class <= C_TYPEDEF; class ++) {\n    q = ((class == C_GLOBAL) || (class == C_STATIC) ||\n                 (class == C_EXTERN)) ? '$' : '%';\n    printf(\"class %d prefix %c\\n\", class, q);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/input154.c",
    "content": "#include <stdio.h>\n\nint main()\n{\n  int x= 5;\n  long y= x;\n  int z= (int)y;\n  printf(\"%d %ld %d\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "63_QBE/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "63_QBE/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "63_QBE/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "63_QBE/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "63_QBE/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "63_QBE/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "63_QBE/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "63_QBE/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "63_QBE/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "63_QBE/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "63_QBE/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "63_QBE/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "63_QBE/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "63_QBE/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "63_QBE/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "63_QBE/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "63_QBE/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "63_QBE/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "63_QBE/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "63_QBE/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "63_QBE/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "63_QBE/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "63_QBE/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "63_QBE/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "63_QBE/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "63_QBE/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "63_QBE/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "63_QBE/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "63_QBE/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "63_QBE/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "63_QBE/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "63_QBE/tests/out.input030.c",
    "content": "int printf(char *fmt);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "63_QBE/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "63_QBE/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "63_QBE/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "63_QBE/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "63_QBE/tests/out.input062.c",
    "content": "65\n66\n66\nThe next two depend on the endian of the platform\n66\n66\n67\n67\n"
  },
  {
    "path": "63_QBE/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "63_QBE/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "63_QBE/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "63_QBE/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "63_QBE/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "63_QBE/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "63_QBE/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "63_QBE/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "63_QBE/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "63_QBE/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "63_QBE/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "63_QBE/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "63_QBE/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "63_QBE/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "63_QBE/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "63_QBE/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "63_QBE/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "63_QBE/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "63_QBE/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "63_QBE/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "63_QBE/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "63_QBE/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "63_QBE/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "63_QBE/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "63_QBE/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "63_QBE/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "63_QBE/tests/out.input115.c",
    "content": "1\n4\n8\n8\n13\n64\n48\n"
  },
  {
    "path": "63_QBE/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "63_QBE/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "63_QBE/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "63_QBE/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "63_QBE/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "63_QBE/tests/out.input122.c",
    "content": "x 0, y 0, x || y 0, x && y 0\nx 0, y 1, x || y 1, x && y 0\nx 1, y 0, x || y 1, x && y 0\nx 1, y 1, x || y 1, x && y 1\n"
  },
  {
    "path": "63_QBE/tests/out.input123.c",
    "content": " 0 infant composite\n 1 infant composite\n 2 infant prime\n 3 infant prime\n 4 infant composite\n 5 infant prime\n 6 infant composite\n 7 infant prime\n 8 infant composite\n 9 infant composite\n10 infant composite\n11 infant prime\n12 infant composite\n13 teen   prime\n14 teen   composite\n15 teen   composite\n16 teen   composite\n17 teen   prime\n18 teen   composite\n19 teen   prime\n"
  },
  {
    "path": "63_QBE/tests/out.input125.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "63_QBE/tests/out.input127.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "63_QBE/tests/out.input128.c",
    "content": "10 10\n15 15\n20 20\n"
  },
  {
    "path": "63_QBE/tests/out.input130.c",
    "content": "Hello world\n"
  },
  {
    "path": "63_QBE/tests/out.input131.c",
    "content": "Doing nothing... nothing done\nx is now 100\n"
  },
  {
    "path": "63_QBE/tests/out.input132.c",
    "content": ""
  },
  {
    "path": "63_QBE/tests/out.input133.c",
    "content": "OK\n"
  },
  {
    "path": "63_QBE/tests/out.input134.c",
    "content": "1st match\n"
  },
  {
    "path": "63_QBE/tests/out.input135.c",
    "content": "testing x\n"
  },
  {
    "path": "63_QBE/tests/out.input136.c",
    "content": "-35\n"
  },
  {
    "path": "63_QBE/tests/out.input137.c",
    "content": "x is 36\n"
  },
  {
    "path": "63_QBE/tests/out.input138.c",
    "content": "0 0 | 0\n0 1 | 0\n1 0 | 0\n1 1 | 1\n0 0 | 0\n0 1 | 1\n1 0 | 1\n1 1 | 1\naptr is NULL or doesn't point at 1\naptr points at 1\n"
  },
  {
    "path": "63_QBE/tests/out.input139.c",
    "content": "same apparently\n"
  },
  {
    "path": "63_QBE/tests/out.input140.c",
    "content": "0\n1\n4\n9\n16\n5 H\n"
  },
  {
    "path": "63_QBE/tests/out.input143.c",
    "content": "One of the three is NULL\nOne of the three is NULL\nOne of the three is NULL\nAll  three  are non-NULL\n"
  },
  {
    "path": "63_QBE/tests/out.input144.c",
    "content": "Unable to open fred: Success\n"
  },
  {
    "path": "63_QBE/tests/out.input145.c",
    "content": "q\nw\ne\nr\ne\n3\n5\n7\n9\n7\n"
  },
  {
    "path": "63_QBE/tests/out.input146.c",
    "content": "q\nw\ne\nr\ne\nr\ne\nr\ne\n\n3\n5\n7\n9\n7\n9\n7\n9\n7\n"
  },
  {
    "path": "63_QBE/tests/out.input147.c",
    "content": "6\n9\n6\n9\n"
  },
  {
    "path": "63_QBE/tests/out.input148.c",
    "content": "i is 1\ni is 2\ni is 3\nleftover owl\n"
  },
  {
    "path": "63_QBE/tests/out.input149.c",
    "content": "1 -4\n2 -8\n3 -12\n4 -16\n5 -21\n6 -27\n7 -34\n8 -42\n9 -51\n10 -61\n11 -72\n12 -84\n"
  },
  {
    "path": "63_QBE/tests/out.input150.c",
    "content": "1 2 3\n4 5 6\n7 8 9\n\n1 2 3\n4 5 fish\n"
  },
  {
    "path": "63_QBE/tests/out.input151.c",
    "content": "0\n5\n7\n9\n9\n"
  },
  {
    "path": "63_QBE/tests/out.input152.c",
    "content": "4 2 4\n"
  },
  {
    "path": "63_QBE/tests/out.input153.c",
    "content": "class 1 prefix $\nclass 2 prefix %\nclass 3 prefix %\nclass 4 prefix $\nclass 5 prefix $\nclass 6 prefix %\nclass 7 prefix %\nclass 8 prefix %\nclass 9 prefix %\nclass 10 prefix %\nclass 11 prefix %\n"
  },
  {
    "path": "63_QBE/tests/out.input154.c",
    "content": "5 5 5\n"
  },
  {
    "path": "63_QBE/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"; exit 1\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n\t    # Stop if our 1st argument is \"stop\"\n\t    if [ $1 = \"stop\" ]\n\t    then exit 1\n\t    fi\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "63_QBE/tests/runtests2",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# Build our compiler if needed\nif [ ! -f ../cwj2 ]\nthen (cd ..; make install; make cwj2)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n          ../cwj2 -o out $i\n          ./out > trial.$i\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n          ../cwj2 $i 2> \"trial.$i\"\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "63_QBE/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// AST tree functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->op = op;\n  n->type = type;\n  n->ctype = ctype;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->sym = sym;\n  n->a_intvalue = intvalue;\n  n->linenum = 0;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, left, NULL, NULL, sym, intvalue));\n}\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// List of AST node names\nstatic char *astname[] = { NULL,\n  \"ASSIGN\", \"ASPLUS\", \"ASMINUS\", \"ASSTAR\",\n  \"ASSLASH\", \"ASMOD\", \"TERNARY\", \"LOGOR\",\n  \"LOGAND\", \"OR\", \"XOR\", \"AND\", \"EQ\", \"NE\", \"LT\",\n  \"GT\", \"LE\", \"GE\", \"LSHIFT\", \"RSHIFT\",\n  \"ADD\", \"SUBTRACT\", \"MULTIPLY\", \"DIVIDE\", \"MOD\",\n  \"INTLIT\", \"STRLIT\", \"IDENT\", \"GLUE\",\n  \"IF\", \"WHILE\", \"FUNCTION\", \"WIDEN\", \"RETURN\",\n  \"FUNCCALL\", \"DEREF\", \"ADDR\", \"SCALE\",\n  \"PREINC\", \"PREDEC\", \"POSTINC\", \"POSTDEC\",\n  \"NEGATE\", \"INVERT\", \"LOGNOT\", \"TOBOOL\", \"BREAK\",\n  \"CONTINUE\", \"SWITCH\", \"CASE\", \"DEFAULT\", \"CAST\"\n};\n\n// Given an AST tree, print it out and follow the\n// traversal of the tree that genAST() follows\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n  int i;\n\n  if (n == NULL)\n    fatal(\"NULL AST node\");\n  if (n->op > A_CAST)\n    fatald(\"Unknown dumpAST operator\", n->op);\n\n  // Deal with IF and WHILE statements specifically\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"IF\");\n      if (n->right) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \"\\n\");\n      dumpAST(n->left, Lfalse, level + 2);\n      dumpAST(n->mid, NOLABEL, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"WHILE, start L%d\\n\", Lstart);\n      Lend = gendumplabel();\n      dumpAST(n->left, Lend, level + 2);\n      if (n->right)\n\tdumpAST(n->right, NOLABEL, level + 2);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE nodes\n  if (n->op == A_GLUE) {\n    level -= 2;\n  } else {\n\n    // General AST node handling\n    for (i = 0; i < level; i++)\n      fprintf(stdout, \" \");\n    fprintf(stdout, \"%s\", astname[n->op]);\n    switch (n->op) {\n      case A_FUNCTION:\n      case A_FUNCCALL:\n      case A_ADDR:\n      case A_PREINC:\n      case A_PREDEC:\n\tif (n->sym != NULL)\n\t  fprintf(stdout, \" %s\", n->sym->name);\n\tbreak;\n      case A_INTLIT:\n\tfprintf(stdout, \" %d\", n->a_intvalue);\n\tbreak;\n      case A_STRLIT:\n\tfprintf(stdout, \" rval label L%d\", n->a_intvalue);\n\tbreak;\n      case A_IDENT:\n\tif (n->rvalue)\n\t  fprintf(stdout, \" rval %s\", n->sym->name);\n\telse\n\t  fprintf(stdout, \" %s\", n->sym->name);\n\tbreak;\n      case A_DEREF:\n\tif (n->rvalue)\n\t  fprintf(stdout, \" rval\");\n\tbreak;\n      case A_SCALE:\n\tfprintf(stdout, \" %d\", n->a_size);\n\tbreak;\n      case A_CASE:\n\tfprintf(stdout, \" %d\", n->a_intvalue);\n\tbreak;\n      case A_CAST:\n\tfprintf(stdout, \" %d\", n->type);\n\tbreak;\n    }\n    fprintf(stdout, \"\\n\");\n  }\n\n  // General AST node handling\n  if (n->left)\n    dumpAST(n->left, NOLABEL, level + 2);\n  if (n->mid)\n    dumpAST(n->mid, NOLABEL, level + 2);\n  if (n->right)\n    dumpAST(n->right, NOLABEL, level + 2);\n}\n"
  },
  {
    "path": "63_QBE/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a primitive pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n\t\t\t    struct symtable *rctype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // For A_LOGOR and A_LOGAND, both types have to be int or pointer types\n  if (op == A_LOGOR || op == A_LOGAND) {\n    if (!inttype(ltype) && !ptrtype(ltype))\n      return (NULL);\n    if (!inttype(ltype) && !ptrtype(rtype))\n      return (NULL);\n    return (tree);\n  }\n  // XXX No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // The tree's type size is too big and we can't narrow\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, NULL, tree, NULL, 0));\n  }\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return (tree);\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when the left tree is of  `void *` type.\n    if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))\n      return (tree);\n  }\n  // We can scale only on add and subtract operations\n  if (op == A_ADD || op == A_SUBTRACT || op == A_ASPLUS || op == A_ASMINUS) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = genprimsize(value_at(rtype));\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, rctype, tree, NULL, rsize));\n      else\n\t// No need to scale, but we need to widen to pointer size\n\treturn (mkastunary(A_WIDEN, rtype, NULL, tree, NULL, 0));\n    }\n  }\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "64_6809_Target/6809triple_test",
    "content": "#!/bin/sh\n#\n# Build the 6809 compiler binaries. Also create front-end shell\n# scripts so that we can run them as if they were native programs.\n#\n# Do this twice to run the triple test on the 6809 compiler binaries.\n#\nmake clean l1dirs.h\nmkdir L1\nwcc \t   -o L1/wcc wcc.c\ncc         -o L1/cpeep cpeep.c\nwcc -m6809 -o L1/_cscan scan.c misc.c\nwcc -m6809 -o L1/_detok detok.c tstring.c\nwcc -m6809 -o L1/_detree -DDETREE detree.c misc.c tree.c\nwcc -m6809 -o L1/_desym desym.c\nwcc -m6809 -o L1/_cparse6809 -DWRITESYMS decl.c expr.c misc.c opt.c \\\n\t\tparse.c stmt.c sym.c tree.c targ6809.c tstring.c types.c\nwcc -m6809 -o L1/_cgen6809 -DSPLITSWITCH cg6809.c cgen.c gen.c misc.c sym.c \\\n\t\ttarg6809.c tree.c types.c\nrm -f l1dirs.h dirs.h\n\n# Make the front-end shell scripts\ndir=`pwd`/L1\nfor i in cscan detok detree desym cparse6809 cgen6809\ndo cat << EOF > L1/$i\n#!/bin/sh\nexec emu6809 $dir/_$i \\$*\nEOF\n\n  chmod +x L1/$i\ndone\n\n# exit 0\n\n# Now we do it all again for L2\nmake l2dirs.h\nmkdir L2\nwcc              -o L2/wcc wcc.c\ncc               -o L2/cpeep cpeep.c\nL1/wcc -m6809 -v -o L2/_cscan scan.c misc.c\nL1/wcc -m6809 -v -o L2/_detok detok.c tstring.c\nL1/wcc -m6809 -v -o L2/_detree -DDETREE detree.c misc.c tree.c\nL1/wcc -m6809 -v -o L2/_desym desym.c\nL1/wcc -m6809 -v -o L2/_cparse6809 -DWRITESYMS decl.c expr.c misc.c opt.c \\\n\t\t\tparse.c stmt.c sym.c tree.c targ6809.c tstring.c types.c\nL1/wcc -m6809 -v -o L2/_cgen6809 -DSPLITSWITCH cg6809.c cgen.c gen.c misc.c sym.c \\\n\t\t\ttarg6809.c tree.c types.c\nrm -f l2dirs.h dirs.h\n\n# Make the front-end shell scripts\ndir=`pwd`/L2\nfor i in cscan detok detree desym cparse6809 cgen6809\ndo cat << EOF > L2/$i\n#!/bin/sh\nexec emu6809 $dir/_$i \\$*\nEOF\n\n  chmod +x L2/$i\ndone\n\nexit 0\n"
  },
  {
    "path": "64_6809_Target/Makefile",
    "content": "# Define the location of the include directory\n# and the location to install the compiler binary.\n# You will need to make TOPDIR and make it writable by you.\n#\nTOPDIR=/opt/wcc\nBINDIR=$(TOPDIR)/bin\nINCQBEDIR=$(TOPDIR)/include/qbe\nINC6809DIR=$(TOPDIR)/include/6809\nLIB6809DIR=$(TOPDIR)/lib/6809\n\nCFLAGS=-g -Wall\n# CFLAGS+= --coverage\n# then gcov *gcno\n\n# Header files and C files for the QBE and 6809 parser phase\n#\nPARSEH= cg.h data.h decl.h defs.h expr.h gen.h misc.h opt.h \\\n\tparse.h stmt.h sym.h target.h tree.h types.h\nPARSEC6809= decl.c expr.c misc.c opt.c parse.c stmt.c sym.c tree.c \\\n\ttarg6809.c tstring.c types.c\nPARSECQBE= decl.c expr.c misc.c opt.c parse.c stmt.c sym.c tree.c \\\n\ttargqbe.c tstring.c types.c\n\n# Header files and C files for the QBE and 6809 code generator phase\n#\nGENH= cg.h data.h defs.h gen.h misc.h sym.h target.h tree.h types.h\nGENC6809= cg6809.c cgen.c gen.c misc.c sym.c targ6809.c tree.c types.c\nGENCQBE= cgqbe.c cgen.c gen.c misc.c sym.c targqbe.c tree.c types.c\n\n# These executables are compiled by the existing C compiler on your system.\n#\nall: wcc cscan detok detree desym cpeep \\\n\tcparse6809 cgen6809 cparseqbe cgenqbe\n\nwcc: wcc.c wcc.h l0dirs.h\n\tcc -o wcc $(CFLAGS) wcc.c\n\ncscan: scan.c defs.h misc.h misc.c\n\tcc -o cscan $(CFLAGS) scan.c misc.c\n\ncpeep: cpeep.c\n\tcc -o cpeep $(CFLAGS) cpeep.c\n\ncparse6809: $(PARSEC6809) $(PARSEH)\n\tcc -o cparse6809 $(CFLAGS) -DWRITESYMS $(PARSEC6809)\n\ncgen6809: $(GENC6809) $(GENH)\n\tcc -o cgen6809 $(CFLAGS) $(GENC6809)\n\ncparseqbe: $(PARSECQBE) $(PARSEH)\n\tcc -o cparseqbe $(CFLAGS) -DWRITESYMS $(PARSECQBE)\n\ncgenqbe: $(GENCQBE) $(GENH)\n\tcc -o cgenqbe $(CFLAGS) $(GENCQBE)\n\ndesym: desym.c defs.h types.h\n\tcc -o desym $(CFLAGS) desym.c\n\ndetok: detok.c tstring.c defs.h\n\tcc -o detok $(CFLAGS) detok.c tstring.c\n\ndetree: detree.c misc.c tree.c misc.h defs.h tree.h\n\tcc -o detree $(CFLAGS) -DDETREE detree.c misc.c tree.c\n\nl0dirs.h:\n\techo \"#define TOPDIR \\\"$(TOPDIR)\\\"\" > l0dirs.h\n\techo \"#define INCQBEDIR \\\"$(INCQBEDIR)\\\"\" >> l0dirs.h\n\techo \"#define INC6809DIR \\\"$(INC6809DIR)\\\"\" >> l0dirs.h\n\techo \"#define BINDIR \\\"$(BINDIR)\\\"\" >> l0dirs.h\n\techo \"#define LIB6809DIR \\\"$(LIB6809DIR)\\\"\" >> l0dirs.h\n\tcp l0dirs.h dirs.h\n\n# Install the compiler built by the external compiler\n#\ninstall: all\n\t@if [ ! -d $(TOPDIR) ]; then echo \"$(TOPDIR) doesn't exit, create it writeable by you\"; exit 1; fi\n\tmkdir -p $(INC6809DIR)\n\tmkdir -p $(INCQBEDIR)\n\tmkdir -p $(BINDIR)\n\tmkdir -p $(LIB6809DIR)\n\trsync -a --exclude RCS include/qbe/. $(INCQBEDIR)\n\trsync -a --exclude RCS include/6809/. $(INC6809DIR)\n\trsync -a --exclude Makefile --exclude RCS --exclude crt0.s \\\n\t\tlib/6809/. $(LIB6809DIR)\n\tcp wcc cscan detok detree desym cpeep \\\n\t  cparse6809 cgen6809 \\\n\t  cparseqbe cgenqbe $(BINDIR)\n\n# These rules are for the compiler to build itself.\n# Use the L1 directory to hold the binaries.\n#\nl1dirs.h: TOPDIR= `pwd`\nl1dirs.h: BINDIR= `pwd`/L1\n\nl1dirs.h:\n\techo \"#define TOPDIR \\\"$(TOPDIR)\\\"\" > l1dirs.h\n\techo \"#define INCQBEDIR \\\"$(INCQBEDIR)\\\"\" >> l1dirs.h\n\techo \"#define INC6809DIR \\\"$(INC6809DIR)\\\"\" >> l1dirs.h\n\techo \"#define BINDIR \\\"$(BINDIR)\\\"\" >> l1dirs.h\n\techo \"#define LIB6809DIR \\\"$(LIB6809DIR)\\\"\" >> l1dirs.h\n\tcp l1dirs.h dirs.h\n\n# These executables are compiled by our own compiler\n#\nl1bins: install L1/wcc L1/cscan L1/cparseqbe L1/cgenqbe \\\n\t\tL1/desym L1/detok L1/detree\n\nL1/wcc: wcc.c wcc.h l1dirs.h\n\tmkdir -p L1\n\twcc -o L1/wcc wcc.c\n\nL1/cscan: scan.c defs.h misc.h misc.c\n\twcc -o L1/cscan scan.c misc.c\n\nL1/cparseqbe: $(PARSECQBE) $(PARSEH)\n\twcc -o L1/cparseqbe -DWRITESYMS $(PARSECQBE)\n\nL1/cgenqbe: $(GENCQBE) $(GENH)\n\twcc -o L1/cgenqbe $(GENCQBE)\n\nL1/desym: desym.c defs.h types.h\n\twcc -o L1/desym desym.c\n\nL1/detok: detok.c tstring.c defs.h\n\twcc -o L1/detok detok.c tstring.c\n\nL1/detree: detree.c misc.c tree.c misc.h defs.h tree.h\n\twcc -o L1/detree -DDETREE detree.c misc.c tree.c\n\n# These rules are for the compiler to build itself a second time.\n# If the binaries match those built the first time, we know that\n# the compiler can successfully compile itself.\n# Use the L2 directory to hold the binaries.\n#\nl2dirs.h: TOPDIR= `pwd`\nl2dirs.h: BINDIR= `pwd`/L2\n\nl2dirs.h:\n\techo \"#define TOPDIR \\\"$(TOPDIR)\\\"\" > l2dirs.h\n\techo \"#define INCQBEDIR \\\"$(INCQBEDIR)\\\"\" >> l2dirs.h\n\techo \"#define INC6809DIR \\\"$(INC6809DIR)\\\"\" >> l2dirs.h\n\techo \"#define BINDIR \\\"$(BINDIR)\\\"\" >> l2dirs.h\n\techo \"#define LIB6809DIR \\\"$(LIB6809DIR)\\\"\" >> l2dirs.h\n\tcp l2dirs.h dirs.h\n\n# These executables are compiled by our own compiler\n#\nl2bins: l1bins L2/wcc L2/cscan L2/cparseqbe L2/cgenqbe \\\n\t\tL2/desym L2/detok L2/detree\n\nL2/wcc: wcc.c wcc.h l2dirs.h\n\tmkdir -p L2\n\tL1/wcc -o L2/wcc wcc.c\n\nL2/cscan: scan.c defs.h misc.h misc.c\n\tL1/wcc -o L2/cscan scan.c misc.c\n\nL2/cparseqbe: $(PARSECQBE) $(PARSEH)\n\tL1/wcc -o L2/cparseqbe -DWRITESYMS $(PARSECQBE)\n\nL2/cgenqbe: $(GENCQBE) $(GENH)\n\tL1/wcc -o L2/cgenqbe $(GENCQBE)\n\nL2/desym: desym.c defs.h types.h\n\tL1/wcc -o L2/desym desym.c\n\nL2/detok: detok.c tstring.c defs.h\n\tL1/wcc -o L2/detok detok.c tstring.c\n\nL2/detree: detree.c misc.c tree.c misc.h defs.h tree.h\n\tL1/wcc -o L2/detree -DDETREE detree.c misc.c tree.c\n\n# Do the triple test: build the compiler with the external compiler,\n# build the compiler with itself and then use this compiler to\n# build the compiler again. The binaries should be identical. Note\n# that the `wcc` binaries are different because the TOPDIR is different.\n#\ntriple: l2bins\n\tmd5sum L1/* L2/* | sort\n\n# Clean up all versions of the compiler\nclean:\n\trm -f wcc cscan detok detree desym cpeep \\\n\t  cparse6809 cgen6809 \\\n\t  cparseqbe cgenqbe \n\trm -f *.o *.s out a.out dirs.h l?dirs.h *.gc??\n\trm -rf L1 L2\n\n# Run the tests with the compiler built with the external compiler\n#\ntest: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests qbe)\n\ntests: test\n\n# Run the 6809 tests\n6test: install tests/runtests\n\t(cd tests; chmod +x runtests; ./runtests 6809)\n"
  },
  {
    "path": "64_6809_Target/Readme.md",
    "content": "# Part 64: Self-compilation on an 8-bit CPU\n\nI'm back with another chapter of this compiler writing journey. This time,\nthe goal is get the compiler to compile itself on a 8-bit CPU from the 1980s.\nIt's been an interesting, sometimes fun, sometimes painful task. Here's a\nsummary of all the work that I've had to do.\n\nFor the CPU, I chose the\n[Motorola 6809](https://en.wikipedia.org/wiki/Motorola_6809). This is\nprobably one of the most sophisticated 8-bit CPUs from the 1980s, with\na bunch of useful addressing modes and, importantly, a useful stack pointer.\n\nWhat makes it difficult to write a compiler for the 6809 is the address space\nlimitation. Like many of the 8-bit CPUs, there only 64K of memory\n(yes, 65,536 _bytes_!) and, on most vintage 6809 systems, a significant\nportion of this is taken up by ROM.\n\nI went in this direction as, in 2023, I decided to try and build a\nsingle board computer (SBC) using the 6809 as the CPU. In particular,\nI wanted to have a machine with at least half a megabyte of memory,\na disk-like storage device, and a Unix-like operating system.\n\nThe result is the [MMU09 SBC](https://github.com/DoctorWkt/MMU09).\nThe project is semi-incomplete; it does have a Unix-like system,\nit does do multitasking, but there is no pre-emptive multitasking.\nEach process gets 63.5K of usable address space (i.e. RAM).\n\nWhile I was working on MMU09, I needed to find a suitable C compiler to\ncompile the code for the operating system, the libraries and the applications.\nI started with [CMOC](http://perso.b2b2c.ca/~sarrazip/dev/cmoc.html) but\neventually switched over to [vbcc](http://www.compilers.de/vbcc.html).\nAlong the way I found Alan Cox's\n[Fuzix Compiler Kit](https://github.com/EtchedPixels/Fuzix-Compiler-Kit)\nwhich is a work-in-progress C compiler for many 8-bit and 16-bit CPUs.\n\nAll of this got me to thinking: is it possible to have the C compiler\nrun _on_ the 6809 and not just cross compile from a more powerful system?\nI thought the Fuzix Compiler Kit might be a contender but, no, it's just\ntoo big to fit on the 6809 itself.\n\nSo here we are with the question/goal: can the \"acwj\" compiler be modified\nto fit and run on a 6809 platform?\n\n## The 6809 CPU\n\nLet's start with a look at the 6809 CPU from a compiler writer's perspective.\nI've already mentioned the 64K address space limitation: that's going to\nrequire the \"acwj\" compiler to be completely restructured to fit. Now let's\nlook at the 6809's architecture.\n\n![](docs/6809_Internal_Registers.png)\n\nCreative Commons CC0 license,\n[Wikipedia](https://commons.wikimedia.org/wiki/File:6809_Internal_Registers.svg)\n\nFor an 8-bit CPU, the 6809 has quite a few registers. Well, it's not like\nthe x64 or a RISC CPU with a bunch of general-purpose registers. There is\na single 16-bit `D` register on which we can do logical and arithmetic\noperations. It can also be accessed as two 8-bit registers `A` and `B`, of\nwhich `B` is the least-significant byte in the `D` register.\n\nWhen doing logical and arithmetic operations, the second operand is\neither a memory location accessed via some addressing mode, or a literal value.\nThe result of the operation is put back in the `D` register: hence, it\n_accumulates_ the operation's result.\n\nTo access memory, there are a bunch of addressing mode to do so. In fact,\nthere are many more available than a compiler needs! We have the index\nregisters `X` and `Y` to, for example, access an element in an array\nwhen we know the base address and `X` holds the element's index.\nWe can also access memory by using a signed constant and the stack pointer\n`S` as the index; this allows us to treat `S` as a \n[frame pointer](https://en.wikipedia.org/wiki/Call_stack#FRAME-POINTER).\nWe can find the local variables of a function at addresses below the\nframe pointer and function arguments at addresses above the frame pointer.\n\nLet's have a look at some examples to make the above a bit clearer:\n\n```\n    ldd #2         # Load D with the constant 2\n    ldd 2          # Load D from addresses 2 and 3 (16 bits)\n    ldd _x         # Load D from the location known as _x\n    ldd 2,s        # Load D from an argument on the stack\n    std -20,s      # Store D to a local variable on the stack\n    leax 8,s       # Get the (effective) address which is S+8\n                   # and store it in the X register\n    ldd 4,x        # Now use that as a pointer to an int array\n                   # and load the value at index 2 - remember\n                   # that D is 16-bits (2 bytes), so 4 bytes\n                   # are two 16-bit \"words\"\n    addd -6,s      # Add the int we just fetched to a local\n                   # variable and save it in the D register\n```\n\nFor more details, I'd recommend that you browse through the\n[6809 datasheet](docs/6809Data.pdf).\nPages 5-6 cover the registers, pages 16-18 cover the addressing modes,\nand pages 25-27 list the available instructions.\n\nBack to targetting the \"acwj\" compiler to the 6809. Well, having a lot\nof addressing modes is great. We can deal with 8-bit values and 16-bit\nvalues, but there are no 32-bit registers. OK, we can sort that out\nsomehow.\n\nBut the biggest problem, apart from the 64K address space,\nis that the \"acwj\" compiler was written for an architecture that has two-\nor three-operand instructions, and with a lot of available registers, e.g.\n\n```\n   load R1, _x\t\t# Bring _x and _y into registers\n   load R2, _y\n   add  R3, R1, R2\t# R3= R1 + R2\n   save R3, _z\t\t# Store the result into _z\n```\n\nThe 6809 usually has the `D` register as one instruction operand, and\nmemory or a literal value as the other operand; the result always ends\nup in the `D` register.\n\n## Keeping the QBE Backend\n\nI also wanted to keep the existing QBE backend in the compiler. I knew\nthat this would be invaluable as I made changes to the compiler - I\ncould run the tests with both the QBE and 6809 backends and compare\nresults. And I could always stress-test the compiler by trying to\nperform the triple test using the QBE backend.\n\nSo now the full goal is: can I take the abstract syntax tree (AST) generated\nby the compiler's parser and use it to generate assembly code for two\ncompletely different architectures: QBE (RISC-like, three-operand instructions)\nand the 6809 (only one register, two-operand instructions with implicit\nsource and destination)? And can I get the compiler to self-compile on\nboth architectures?\n\nThis is going to be an interesting journey!\n\n## The Code Generator Contract\n\nNow that we are going to have two different backends, we need a \"contract\"\nor API between the architecture-independent part of the code generator\n([gen.c](gen.c)) and each architecture-dependent part. This is now the\nlist of functions defined in [gen.h](gen.h).\n\nThe basic API is the same as before. We pass in one or more \"register numbers\"\nand get back a register number that holds the result. One difference this\ntime is that many of the functions receive the architecture-independent `type`\nof the operands; this is defined in [defs.h](defs.h):\n\n```\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n```\n\nIf you look at the QBE code generator in [cgqbe.c](cgqbe.c), it is\npretty much the same as in the last chapter in this \"acwj\" journey.\nOne thing to note is that I've abstracted a few of the functions into\na separate file, [targqbe.c](targqbe.c), as the parser and code\ngenerator now live in different programs.\n\nNow let's look at the 6809 code generator.\n\n## 6809-Specific Types and the D Register\n\nThe big problem is how to have the idea of multiple registers on the 6809.\nI'll cover that in the next section, but I need to take a short detour\nfirst.\n\nEach architecture-dependent code generator gets given the type of\noperands: P_CHAR, P_INT etc. For the 6809 code generator, we convert\nthese into 6809-specific types, as defined in [cg6809.c](cg6809.c):\n\n```\n#define PR_CHAR         1\t// size 1 byte\n#define PR_INT          2\t// size 2 bytes\n#define PR_POINTER      3\t// size 2 bytes\n#define PR_LONG         4\t// size 4 bytes\n```\n\nIn this file, you will see a lot of this sort of code:\n\n```\n  int primtype= cgprimtype(type);\n\n  switch(primtype) {\n    case PR_CHAR:\n      // Code to generate char operations\n    case PR_INT:\n    case PR_POINTER:\n      // Code to generate int operations\n    case PR_LONG:\n      // Code to generate long operations\n  }\n```\n\nEven though `PR_INT` and `PR_POINTER` are the same size and generate the same\ncode, I've kept the ideas separate. That's because pointers are really\nunsigned whereas `int`s are signed. Later on, if I get to adding signed and\nunsigned types to the compiler, I already have a head start here in the\n6809 backend.\n\n## How Registers When No Registers?\n\nNow, back to the main problem:\nif the code generator API uses register numbers, how do we write a\n6809 backend when this CPU only has a single accumulator, `D`?\n\nWhen I began writing the 6809 backend, I started with a set of\n4-byte memory locations called `R0, R1, R2` etc. You can still see\nthem in [lib/6809/crt0.s](lib/6809/crt0.s):\n\n```\nR0:     .word   0\n        .word   0\nR1:     .word   0\n        .word   0\n...\n```\n\nThis helped me get the 6809 backend up and running, but the code\ngenerated was awful. For example, this C code:\n\n```\n  int x, y, z;\n  ...\n  z= x + y;\n```\n\ngets translated to:\n\n```\n  ldd  _x\n  std  R0\n  ldd  _y\n  std  R1\n  ldd  R0\n  addd R1\n  std  R2\n  ldd  R2\n  std  _z\n```\n\nThen I realised: the 6809 is very \"address\"-oriented: there are a bunch\nof addressing modes, and most instructions have an address (or a literal)\nas an operand. So, let's keep a list of \"_locations_\".\n\nA location is one of the following, defined in [cg6809.c](cg6809.c):\n\n```\nenum {\n  L_FREE,               // This location is not used\n  L_SYMBOL,             // A global symbol with an optional offset\n  L_LOCAL,              // A local variable or parameter\n  L_CONST,              // An integer literal value\n  L_LABEL,              // A label\n  L_SYMADDR,            // The address of a symbol, local or parameter\n  L_TEMP,               // A temporarily-stored value: R0, R1, R2 ...\n  L_DREG                // The D location, i.e. B, D or Y/D\n};\n```\n\nand we keep a list of free or in-use locations which have this structure:\n\n```\nstruct Location {\n  int type;             // One of the L_ values\n  char *name;           // A symbol's name\n  long intval;          // Offset, const value, label-id etc.\n  int primtype;         // 6809 primitive type\n};\n```\n\nExamples:\n\n - a global `int x` would be an L_SYMBOL with `name` set to \"x\" and\n   `primtype` set to PR_INT.\n - a local `char *ptr` would be an L_LOCAL with no name, but the\n   `intval` would be set to its offset in the stack frame, e.g. -8.\n   `primtype` would be PR_POINTER.\n   If it were a function parameter, the offset would be positive.\n - if the operand was something like `&x` (the address of `x`),\n   then the location would be an L_SYMADDR with `name` set to \"x\".\n - a literal value like 456 would be an L_CONST with the `intval`\n   set to 456 and `primtype` set to PR_INT.\n - finally, if the operand is already in the `D` register, we\n   would have an L_DREG location with a certain PR_ type.\n\nSo, locations stand in for registers. We have an array of 16 locations:\n\n```\n#define NUMFREELOCNS 16\nstatic struct Location Locn[NUMFREELOCNS];\n```\n\nLet's take a look at the code to generate addition on the 6809.\n\n```\n// Add two locations together and return\n// the number of the location with the result\nint cgadd(int l1, int l2, int type) {\n  int primtype= cgprimtype(type);\n\n  load_d(l1);\n\n  switch(primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\taddb \"); printlocation(l2, 0, 'b'); break;\n    case PR_INT:\n    case PR_POINTER:\n      fprintf(Outfile, \"\\taddd \"); printlocation(l2, 0, 'd'); break;\n      break;\n    case PR_LONG:\n      fprintf(Outfile, \"\\taddd \"); printlocation(l2, 2, 'd');\n      fprintf(Outfile, \"\\texg y,d\\n\");\n      fprintf(Outfile, \"\\tadcb \"); printlocation(l2, 1, 'f');\n      fprintf(Outfile, \"\\tadca \"); printlocation(l2, 0, 'e');\n      fprintf(Outfile, \"\\texg y,d\\n\");\n  }\n  cgfreelocn(l2);\n  Locn[l1].type= L_DREG;\n  d_holds= l1;\n  return(l1);\n}\n```\n\nWe first determine the 6809 type from the generic operand type.\nThen we load the value from the first location `l1` into the `D` register.\nThen, based on the 6809 type, we output the right set of instructions\nand print the second location `l2` after each instruction.\n\nOnce the addition is done, we free the second location and mark\nthat the first location `l1` is now the `D` register. We also note\nthat `D` is now in-use before returning.\n\nUsing the idea of locations, the C code `z= x + y` now gets translated to:\n\n```\n  ldd  _x\t; i.e. load_x(l1);\n  addd _y\t; i.e. fprintf(Outfile, \"\\taddd \"); printlocation(l2, 2, 'd');\n  std  _z\t; performed in another function, cgstorglob()\n```\n\n## Dealing with Longs\n\nThe 6809 has 8-bit and 16-bit operations, but the compiler needs to\nsynthesize operations on 32-bit longs. Also, there is no 32-bit register.\n\n> Aside: the 6809 is big-endian. If the `long` value of 0x12345678\n> was stored in a `long` variable named `foo`, then 0x12 would be\n> at `foo` offset 0, 0x34 at `foo` offset 1, 0x56 at `foo` offset\n> 2 and 0x78 at `foo` offset 3.\n\nI've borrowed the idea for longs that Alan Cox uses in the\n[Fuzix Compiler Kit](https://github.com/EtchedPixels/Fuzix-Compiler-Kit).\nWe use the `Y` register to hold the top-half of a 32-bit long with the\n`D` register holding the lower half:\n\n![](docs/long_regs.png)\n\nThe 6809 already calls the lower half of the `D` register the `B`\nregister, used for 8-bit operations. And there is the `A` register\nwhich is the top half of the `D` register.\n\nLooking at the above `cgadd()` code, you can see that, if `x`, `y`\nand `z` were `long`s not `int`s, we would generate:\n\n```\n  ldd  _x+2\t; Get lower half of _x into D\n  ldy  _x+0\t; Get upper half of _x into Y\n  addd _y+2\t; Add lower half of _y to D\n  exg  y,d\t; Swap Y and D registers\n  adcb _y+1\t; Add _y offset 1 to the B register with carry\n  adca _y+0\t; Add _y offset 0 to the A register with carry\n  exg  y,d\t; Swap Y and D registers back again\n  std  _z+2\t; Finally store D (the lower half) in _z offset 2\n  sty  _z\t; and Y (the upper half) in _z offset 0\n```\n\nIt's a bit of a pain: there is a 16-bit `addd` operation with no carry\nbut there is no 16-bit addition operation with carry. Instead, we have to\nperform two 8-bit additions with carry to get the same result.\n\nThis inconsistency with the available 6809 operations\nmakes the 6809 code generator code annoyingly ugly in places.\n\n# printlocation()\n\nA lot of the work in handling locations is performed by the `printlocation()`\nfunction. Let's break it down into a few stages.\n\n```\n// Print a location out. For memory locations\n// use the offset. For constants, use the\n// register letter to determine which part to use.\nstatic void printlocation(int l, int offset, char rletter) {\n  int intval;\n\n  if (Locn[l].type == L_FREE)\n    fatald(\"Error trying to print location\", l);\n\n  switch(Locn[l].type) {\n    case L_SYMBOL: fprintf(Outfile, \"_%s+%d\\n\", Locn[l].name, offset); break;\n    case L_LOCAL: fprintf(Outfile, \"%ld,s\\n\",\n                Locn[l].intval + offset + sp_adjust);\n        break;\n    case L_LABEL: fprintf(Outfile, \"#L%ld\\n\", Locn[l].intval); break;\n    case L_SYMADDR: fprintf(Outfile, \"#_%s\\n\", Locn[l].name); break;\n    case L_TEMP: fprintf(Outfile, \"R%ld+%d\\n\", Locn[l].intval, offset);\n        break;\n    ...\n```\n\nIf the location is L_FREE, then there is no point in trying to print it!\nFor symbols, we print out the symbol's name followed by the offset.\nThat way, for `int`s and `long`s, we can get access to all 2 or 4 bytes\nthat make up the symbol: `_x+0`, `_x+1`, `_x+2`, `_x+3`.\n\nFor locals and function parameters, we print out the position in the\nstack frame (i.e. `intval` with the offset added on). So if a local\n`long` variable `fred` is on the stack at position -12, we can get\naccess to all four bytes with `-12,s`, `-11,s`, `-10,s`, `-9,s`.\n\nYes, there is something called `sp_adjust` here. I'll talk about that soon!\n\nNow, L_TEMP locations. As with all previous versions of the compiler,\nsometimes we have to store intermediate results somewhere, e.g.\n\n```\n  int z= (a + b) * (c - d) / (e + f) * (g + h - i) * (q - 3);\n```\n\nWe have five intermediate results in parentheses which we need\nbefore we can do the multiplies and divides. Well, those original\npretend registers R0, R1, R2 ... become useful now! When I need\ntemporary storage for intermediate results, I just allocate these\nlocations and store the intermediate results here. There are functions\n`cgalloctemp()` and `cgfreealltemps()` in [cg6809.c](cg6809.c) to do this.\n\n# printlocation() and Literal Values\n\nFor most locations, we can simply print out the location's name or\nposition on the stack, plus the offset we need. The code generator\nhas already printed out the instruction to run, so:\n\n```\n  ldb _x+0\t; Will load one byte from _x into B\n  ldd _x+0\t; Will load two bytes from _x into D\n```\n\nBut for literal values, e.g. 0x12345678, do we need to print out\nthe 0x78 on the end, or perhaps the 0x5678? Or do we need (in the\naddition code), access to the 0x34 and also the 0x12?\n\nThat is why there is the `rletter` parameter to `printlocation()`:\n\n```\nstatic void printlocation(int l, int offset, char rletter);\n```\n\nWhen we are printing out literals, we use this to choose which\npart and how much of the literal value. I've chosen values that\nreflect the 6809's register names, but I also made a few up. For\nliteral 0x12345678:\n\n - 'b' prints out the 0x78 part\n - 'a' prints out the 0x56 part\n - 'd' prints out the 0x5678 part\n - 'y' prints out the 0x1234 part\n - 'f' prints out the 0x34 part\n - 'e' prints out the 0x12 part\n\n## Helper Functions\n\nThere are several operations which the compiler needs to perform\nbut which the 6809 has no instruction: multiplication,\ndivision, shifts by multiple bits etc.\n\nTo solve this problem, I've borrowed several of the helper functions from the\n[Fuzix Compiler Kit](https://github.com/EtchedPixels/Fuzix-Compiler-Kit).\nThey are in the archive file `lib/6809/lib6809.a`. The function\n`cgbinhelper()` in [cg6809.c](cg6809.c):\n\n```\n// Run a helper subroutine on two locations\n// and return the number of the location with the result\nstatic int cgbinhelper(int l1, int l2, int type,\n                                char *cop, char *iop, char *lop);\n```\n\ngets the value from the two locations `l1` and `l2`, pushes them on\nthe stack and then calls one of the three char/int/long helper functions\nwith names in `cop`, `iop` and `lop`. Thus, the function in the code\ngenerator to do multiplication is simply:\n\n```\n// Multiply two locations together and return\n// the number of the location with the result\nint cgmul(int r1, int r2, int type) {\n  return(cgbinhelper(r1, r2, type, \"__mul\", \"__mul\", \"__mull\"));\n}\n```\n\n# Tracking Positions of Locals and Parameters\n\nA function's local variables or parameters are kept on the stack, and\nwe access them by using their offset relative to the stack pointer, e.g.\n\n```\n  ldd -12,s     ; Load the local integer variable which is 12 bytes\n                ; below the stack pointer\n```\n\nBut there's a problem. What if the stack pointer moves? Consider the code:\n\n```\nint main() {\n int x;\n \n x= 2; printf(\"%d %d %d\\n\", x, x, x);\n return(0);\n}\n\n```\n\n`x` might be at offset 0 relative to the stack pointer. But when we call\n`printf()`, we push a copy of `x` on the stack. Now the real `x` is at\nposition 2 etc. So we actually have to generate the code:\n\n```\n  ldd 0,s\t; Get x's value\n  pshs d\t; Push it on the stack\n  ldd 2,s\t; Get x's value, note new offset\n  pshs d\t; Push it on the stack\n  ldd 4,s\t; Get x's value, note new offset\n  pshs d\t; Push it on the stack\n  ldd #L2\t; Get the address of the string \"%d %d %d\\n\"\n  pshs d\t; Push it on the stack\n  lbsr _printf\t; Call printf()\n  leas 8,s\t; Pull the 8 bytes of arguments off the stack\n```\n\nHow do we track what the current offset of locals and parameters are?\nThe answer is the `sp_adjust` variable in [cg6809.c](cg6809.c). Each\ntime we push something on the stack, we add the number of bytes pushed\nto `sp_adjust`. Similarly, when we pull from the stack or move the\nstack pointer up, we subtract that amount from `sp_adjust`. Example:\n\n```\n// Push a location on the stack\nstatic void pushlocn(int l) {\n  load_d(l);\n\n  switch(Locn[l].primtype) {\n    ...\n    case PR_INT:\n      fprintf(Outfile, \"\\tpshs d\\n\");\n      sp_adjust += 2;\n      break;\n    ...\n  }\n  ...\n}\n```\n\nAnd in `printlocation()` when we print out locals and parameters:\n\n```\n    case L_LOCAL: fprintf(Outfile, \"%ld,s\\n\",\n                Locn[l].intval + offset + sp_adjust);\n```\n\nThere is also a bit of error checking when we get to the end of\ngenerating a function's assembly code:\n\n```\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  ...\n  if (sp_adjust !=0 ) {\n    fprintf(Outfile, \"; DANGER sp_adjust is %d not 0\\n\", sp_adjust);\n    fatald(\"sp_adjust is not zero\", sp_adjust);\n  }\n}\n```\n\nThat's about all I want to cover in terms of 6809 assembly code generation.\nYes, the code in [cg6809.c](cg6809.c) has to deal with the vagaries of the\n6809 instruction set, which is why [cg6809.c](cg6809.c) is so much bigger\nthan [cgqbe.c](cgqbe.c). But I (hope I) have put enough comments in\n[cg6809.c](cg6809.c) so that you can follow along and understand what it\nis doing.\n\nThere are a few tricky things like tracking when the `D` register is\nin-use or free, and I'm sure I still haven't quite got the synthesis of\nall the `long` operations right.\n\nNow we need to cover a much bigger topic, that of\nthe 6809's 64K address limitation.\n\n## Fitting a Compiler into 65,536 Bytes\n\nThe original \"acwj\" compiler was a single executable. It read from the\nC pre-processor's output, did the scanning, parsing and code generation,\noutputting assembly code. It kept the symbol table and the AST tree\nfor each function in memory, and never bothered to free data structures\nonce they were used.\n\nNone of this is going to help fit the compiler into 64K of memory!\nSo, my approach for 6809 self-compilation was to:\n\n1. Break the compiler up into a number of phases. Each phase\n   does one part of the overall compilation task, and the\n   phases use intermediate files to communicate.\n2. Keep as little of the symbol table and AST trees in memory\n   as we can get away with. Instead, these are kept in files\n   and we have functions to read/write them as required.\n3. Try to garbage collect unused data structures with `free()`\n   wherever we can.\n\nLet's look at all three in turn.\n\n## The Seven Compiler Phases\n\nThe compiler is now arranged to have seven phases, each one with\nits own executable:\n\n1. An external C pre-processor interprets #include, #ifdef\n   and the pre-processor macros.\n2. The lexer reads the pre-processor output and produces a\n   token stream.\n3. The parser reads the token stream and creates\n   a symbol table plus a set of AST trees.\n4. The code generator uses the AST trees and\n   the symbol table and generates assembly code.\n5. An external peephole optimiser improves the assembly code.\n6. An external assembler produces object files.\n7. An external linker takes `crt0.o`, the object files and\n   several libraries and produces a final executable.\n\nWe now have a frontend program [wcc.c](wcc.c) that co-ordinates all\nthe phases. The lexer is the program called `cscan`. The parser is\n`cparse6809` or `cparseqbe`. The code generator is `cgen6809` or\n`cgenqbe`, and the peephole optimiser is `cpeep`. All of these\n(via `make install`) get installed in `/opt/wcc/bin`.\n\nIt's understandable that there are two code generators, but why are\nthere two parsers? The answer is that `sizeof(int)`, `sizeof(long)`\netc. are different on each architecture, so the parser needs to\nhave this information as well as the code generator. Hence the\nfiles [targ6809.c](targ6809.c) and [targqbe.c](targqbe.c) which\nget compiled into the parsers and the code generators.\n\n> Aside: the 6809 has a peephole optimiser. The QBE backend uses\n> the `qbe` program to convert QBE code to x64 code. I guess that's\n> also a form of optimisation :-)\n\n## Intermediate Files\n\nBetween all of these seven phases, we need intermediate files to\nhold the phases' outputs. Normally they get deleted at the end of\ncompilation, but you can keep them if you use the `-X` command-line\nflag with `wcc`.\n\nThe C pre-processor's output is stored in a temporary file ending\nwith `_cpp`, e.g. `foo.c_cpp` if we are compiling `fred.c`.\n\nThe tokeniser's output is stored in a temporary file ending\nwith `_tok`. We have a program called [detok.c](detok.c) which you\ncan use to dump a token file into readable format.\n\nThe parser produces a symbol table file ending with `_sym` and\na set of AST trees that get stored in a file ending with `_ast`.\nWe have programs [desym.c](desym.c) and [detree.c](detree.c)\nto dump the symbol table and AST tree files.\n\nRegardless of the CPU, the code generator always outputs\nunoptimised assembly code in a file ending with `_qbe`.\nThis gets read by either `qbe` or `cpeep` to produce the\noptimised assembly code in a temporary file that ends in `_s`.\n\nThe assembler then assembles this file to produce object files\nending in `.o`, which are then linked by the linker to produce\nthe final executable file.\n\nLike other compilers, `wcc` has the `-S` flag to output assembly\nto a file ending with `.s` (and then stop), and the `-c` flag\nto output object files and then stop.\n\n## Format of the Symbol Table and AST files\n\nI took a simple approach for these files which I'm sure could be\nimproved. I simply write each `struct symtable` and `struct ASTnode`\nnodes (see [defs.h](defs.h)) directly to the files using `fwrite()`.\n\nMany of these have an associated string: symbol names, for example,\nand AST nodes that hold string literals. For these I just `fwrite()`\nout the string including the NUL byte at the end.\n\nReading the nodes back in is simple: I just `fread()` the size of\neach struct. But then I have to read back in the NUL-terminated\nstring if there is one. There isn't a good C library function to do\nthis, so in [misc.c](misc.c) there is a function called `fgetstr()` to\ndo this.\n\nOne problem with dumping in-memory structures out to disk is that\nthe pointers in the structures lose their meaning: when the structure\nis reloaded, it's going to end up in another part of memory. Any \npointer value becomes invalid.\n\nTo solve this, both the symbol table structure and the ASTnode structure\nnow have numeric ids, both for the node itself and the nodes it points to.\n\n```\n// Symbol table structure\nstruct symtable {\n  char *name;                   // Name of a symbol\n  int id;                       // Numeric id of the symbol\n  ...\n  struct symtable *ctype;       // If struct/union, ptr to that type\n  int ctypeid;                  // Numeric id of that type\n};\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  ...\n  struct ASTnode *left;         // Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  int nodeid;                   // Node id when tree is serialised\n  int leftid;                   // Numeric ids when serialised\n  int midid;\n  int rightid;\n  ...\n};\n```\n\nThe reading-in code for both is tricky as we have to find and reattach\nnodes. The bigger question is: how much of each file do we bring in\nand keep in memory?\n\n## Structures In-Memory vs. On-Disk\n\nThe tension here is that, if we keep too many symbol table and AST nodes\nin memory, we will run out of memory. But if we put them out into files\nthen we might have to do a lot of file read/write operations when we\nneed access to the nodes.\n\nAs with most problems of this type, we just choose one heuristic that does\na good enough job. One extra constraint here is that we might choose\na heuristic which does a great job, but it requires a lot of code which\nitself puts pressure on available memory.\n\nSo, here is what I've chosen. It can be replaced, but it's what I've got\nfor now.\n\n## Writing Symbol Table Nodes\n\nThe parse phase finds symbols and determines their type etc. So it is\nresponsible for writing the symbols to a file.\n\nOne big change in the compiler is that there is now only a single symbol\ntable, not a set of tables. Each symbol in the unified table now has\na structural type and a visibility (in [defs.h](defs.h)):\n\n```\n// A symbol in the symbol table is\n// one of these structural types.\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY, S_ENUMVAL, S_STRLIT,\n  S_STRUCT, S_UNION, S_ENUMTYPE, S_TYPEDEF, S_NOTATYPE\n};\n\n// Visibilty class for symbols\nenum {\n  V_GLOBAL,                     // Globally visible symbol\n  V_EXTERN,                     // External globally visible symbol\n  V_STATIC,                     // Static symbol, visible in one file\n  V_LOCAL,                      // Locally visible symbol\n  V_PARAM,                      // Locally visible function parameter\n  V_MEMBER                      // Member of a struct or union\n};\n```\n\nOK, so I lied a little bit :-) There are actually three symbol tables:\none for generic symbols, one for types (structs, unions, enums, typedefs)\nand a temporary one which is used to build the member list for\nstructs, unions and functions.\n\nIn [sym.c](sym.c), the `serialiseSym()` function writes a symbol table\nnode and any associated string out to the file. One optimisation is\nthat, as nodes are given montonically increasing ids, we can record\nthe highest symbol id we have already written out, and not (re)write\nsymbols at or below this id.\n\nThe function `flushSymtable()` in the same file walks the type list and\nthe generic symbol list and calls `serialiseSym()` to write each node out.\n\nIn the same file, `freeSym()` frees the memory that a symbol entry\noccupies. This is the node itself, any associated name and also\nany initialisation list (i.e. for global symbols, e.g. `int x= 27;`).\nSymbols like structs, unions and functions also have a list of member\nsymbols - the fields in structs and unions, and the locals and parameters\nof a function. These also get freed.\n\nThe function `freeSymtable()` in [sym.c](sym.c) walks these lists\nand calls `freeSym()` to free each node.\n\nNow, the question is: when is it safe to flush and free the symbol table\nin the parser? The answer is: we can flush the symbol table out after\neach function. But we can't free the symbol table, as the parser needs\nto look up pre-defined types and pre-defined symbols, e.g.\n\n```\n  z= x + y;\n```\n\nWhat types do these have, and are they compatible? Are they locals,\narguments or globals? Have they even been declared? We need the full\nsymbol table for this.\n\nSo in [decl.c](decl.c) at the end of `function_declaration()`:\n\n```\n  ...\n  flushSymtable();\n  Functionid= NULL;\n  return (oldfuncsym);\n}\n```\n\n## Reading Symbol Table Nodes\n\nThe 6809 code generator, code-wise, is pretty big. It takes about 30K\nof RAM, so we have to work hard to not waste the remaining RAM. In\nthe code generator, we only load symbols if we need them. And, each\nsymbol might require knowledge of one or more symbols, e.g. a variable\nmight be of type `struct foo`, so now we need to load the `struct foo`\nsymbol and all of the symbols which are the fields of that structure.\n\nAn issue is that the symbols are written out in order of when they are\nparsed, but we need to find symbols by their name or by their id.\nExample:\n\n```\n  struct foo x;\n```\n\nWe have to search for the `x` symbol by name. That node has the `ctypeid` for\nthe `foo` symbol, so we need to search for that symbol by id.\n\nThe majority of the work here is done by `loadSym()` in [sym.c](sym.c):\n\n```\n// Given a pointer to a symtable node, read in the next entry\n// in the on-disk symbol table. Do this always if loadit is true.\n// Only read one node if recurse is zero.\n// If loadit is false, load the data and return true if the symbol\n// a) matches the given name and stype or b) matches the id.\n// Return -1 when there is nothing left to read.\nstatic int loadSym(struct symtable *sym, char *name,\n                   int stype, int id, int loadit, int recurse) {\n ...\n}\n```\n\nI won't go through the code, but there a few things to note.\nWe can search by `stype` and `name`, e.g. an S_FUNCTION called `printf()`.\nWe can search by numeric id. Sometimes we want to recursively fetch nodes:\nthis happens because a symbol with members (e.g. a struct) gets written\nout immediately followed by the members. Finally, we can just read in\nthe next symbol always if `loadit` is set, e.g. when reading in members.\n\nThe `findSyminfile()` function simply goes back to the start of the symbol\nfile each time, and loops calling `loadSym()` until either the symbol\nrequired is found or we reach the end of the file. Not very efficient, is it?\n\nThe old compiler code had functions\n\n```\nstruct symtable *findlocl(char *name, int id);\nstruct symtable *findSymbol(char *name, int stype, int id);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\n```\n\nThey are still here, but different. We first search in memory for the\nrequired symbol, then call `findSyminfile()` if the symbol isn't in\nmemory. When a symbol is loaded from the file, it gets linked into the\nin-memory symbol table. Thus, we build up a cache of symbols as the\ncode generator needs them.\n\nTo ease memory, we should flush and free the symbol table periodically\nin the code generator. In [cgen.c](cgen.c) which has the main loop for\nthe code generator:\n\n```\n  while (1) {\n    // Read the next function's top node in from file\n    node= loadASTnode(0, 1);\n    if (node==NULL) break;\n\n    // Generate the assembly code for the tree\n    genAST(node, NOLABEL, NOLABEL, NOLABEL, 0);\n\n    // Free the symbols in the in-memory symbol tables.\n    freeSymtable();\n  }\n```\n\nOne minor issue that bit me when rewriting the compiler was that there\nare global symbols which are initialised and need to have assembly\ninstructions generated for them. So, just above the above loop there\nis a call to a function called `allocateGlobals()`. This, in turn,\ncalls a function in [sym.c](sym.c) called `loadGlobals()` which\nreads in any global symbols. Now we can call the appropriate\ncode generator function as we walk the list of global symbols.\nAt the end of `allocateGlobals()` we can `freeSymtable()`.\n\nAnd I've got one last comment. All of this works because there are not\nthat many symbols in any C program, also taking into account the header\nfiles that get included. But if this were a real, production, compiler\non a real Unix-like system, argh!! A typical program will pull in a\ndozen or so header files, each with dozens of typedefs, structs, enum\nvalues etc. We would run out of memory in no time.\n\nSo this all works but it's not scalable.\n\n## Writing AST Nodes\n\nNow on to the AST nodes. The first point I need to make is that there\nsimply isn't enough memory to build the AST tree for a function, then\nwrite it out (or read it in). The bigger functions that we need to\ndeal with have 3,000 or more AST nodes. They simply won't fit into 64K\nof RAM by themselves.\n\nWe can only keep a limited number of AST nodes in memory, but how?\nAfter all it's a tree. For any node, when do we need the sub-trees below it\nand when can we prune the tree?\n\nIn the top-level parser file [parse.c](parse.c) there is function called\n`serialiseAST()` which writes the given node and its children out to disk.\nThis function gets called in a few places.\n\nIn `compound_statement()` in [stmt.c](stmt.c):\n\n```\n  while (1) {\n    ...\n    // Parse a single statement\n    tree = single_statement();\n\n    ...\n        left = mkastnode(A_GLUE, P_NONE, NULL, left, NULL, tree, NULL, 0);\n\n        // To conserve memory, we try to optimise the single statement tree.\n        // Then we serialise the tree and free it. We set the right pointer\n        // in left NULL; this will stop the serialiser from descending into\n        // the tree that we already serialised.\n        tree = optimise(tree);\n        serialiseAST(tree);\n        freetree(tree, 0);\n    ...\n  }\n```\n\nSo, each time there is a single statement, we parse this statement, build\nup the AST tree for it and then dump it to disk.\n\nAnd at the end of `function_declaration()` in [decl.c](decl.c):\n\n```\n  // Serialise the tree\n  serialiseAST(tree);\n  freetree(tree, 0);\n\n  // Flush out the in-memory symbol table.\n  // We are no longer in a function.\n  flushSymtable();\n  Functionid= NULL;\n\n  return (oldfuncsym);\n```\n\nThis writes out the S_FUNCTION node which identifies the top AST node of the\nfunction.\n\nThe code snippets above reference `freetree()`. Here it is in\n[tree.c](tree.c):\n\n```\n// Free the contents of a tree. Possibly\n// because of tree optimisation, sometimes\n// left and right are the same sub-nodes.\n// Free the names if asked to do so.\nvoid freetree(struct ASTnode *tree, int freenames) {\n  if (tree==NULL) return;\n\n  if (tree->left!=NULL) freetree(tree->left, freenames);\n  if (tree->mid!=NULL) freetree(tree->mid, freenames);\n  if (tree->right!=NULL && tree->right!=tree->left)\n                                        freetree(tree->right, freenames);\n  if (freenames && tree->name != NULL) free(tree->name);\n  free(tree);\n}\n```\n\n## Reading AST Nodes\n\nI fought for quite a while to find a good approach for reading AST\nnodes back in to the code generator. We have to do two things:\n\n1. Find each function's top node and read it in.\n2. Once we have an AST node, read in its children using their ids.\n\nMy first approach was, like the symbol table, rewind to the start\nof the file each time I did a search. OK, so that made the compilation \nof an 1,000 line file take about 45 minutes. No, that's not good.\n\nI did think of trying to cache the numeric ids, type (S_FUNCTION or not)\nand file offset in memory. That's not going to work either. For each\nAST node that would be:\n\n - 2 bytes for the id\n - 1 byte for the S_FUNCTION boolean\n - 4 bytes for the file offset\n\nAn AST file with, say, 3,000 nodes now needs a 21,000 byte cache in memory.\nRidiculous!\n\nInstead, I build a list of node file offsets in a separate temporary file.\nThis is done by the `mkASTidxfile()` function in [tree.c](tree.c). The file\nis simply a sequence of offset values, each 4 bytes long. Position 0 holds\nthe offset for id 0, position 4 the offset for id 1 etc.\n\nAs we will need to find each function's top node in turn, and there are\nusually not many functions in a file, I chose to record all the S_FUNCTION\nnodes' offsets in an in-memory list:\n\nIn [tree.c](tree.c), we have:\n\n```\n// We keep an array of AST node offsets that\n// represent the functions in the AST file\nlong *Funcoffset;\n\n```\n\nThis gets `malloc()`d and `realloc()`d and grows to contain all the\nfunction offsets. The last value is 0 because the id value 0 never\ngets allocated in the parser.\n\nNow, how do we use all of this information? In the same file there is a\nfunction called `loadASTnode()`:\n\n```\n// Given an AST node id, load that AST node from the AST file.\n// If nextfunc is set, find the next AST node which is a function.\n// Allocate and return the node or NULL if it can't be found.\nstruct ASTnode *loadASTnode(int id, int nextfunc) {\n  ...\n}\n```\n\nWe can load a node given its id, or we can just load the next S_FUNCTION\nnode. We use the temporary file with the offsets to quickly find where\nthe node we want is positioned in the main AST file. Nice and simple!\n\n## Using loadASTnode() and Freeing AST nodes\n\nUnfortunately, there is not a single place where we can call\n`loadASTnode()`. Anywhere in the architecture-independent generation code\nin [gen.c](gen.c), where we previously used the pointers `n->left`, `n->mid` or\n`n->right`, we now have to call `loadASTnode()`, e.g.\n\n```\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n           int loopendlabel, int parentASTop) {\n  struct ASTnode *nleft, *nmid, *nright;\n\n  // Load in the sub-nodes\n  nleft=loadASTnode(n->leftid,0);\n  nmid=loadASTnode(n->midid,0);\n  nright=loadASTnode(n->rightid,0);\n  ...\n}\n```\n\nYou will find about fifteen calls to `loadASTnode()` in [gen.c](gen.c).\n\nBack in the parser, we could parse a single statement and then call\n`freetree()` once we have written it out to disk. Here in the code\ngenerator, I decided to be more specific. Once I'd definitely finished\nusing an AST node, I call the function `freeASTnode()` defined in\n[tree.c](tree.c) to free its memory. You will find about twelve calls\nto this function in the code generator.\n\nThat's about it for the changes to the symbol table and AST node handling.\n\n## General Memory Freeing\n\nBack up when I started talking about trying to fit the compiler into 64K,\nmy third point was: try to garbage collect unused data structures with\n`free()` wherever we can.\n\nWell, C is probably the worst language to try and do garbage collection!\nFor a while I tried to sprinkle `free()`s where I thought they would\nwork but then the compiler would either segfault or, worse, use a\nnode that had been overwritten and go into crazy behaviour mode.\n\nFortunately, I've been able to get down to four main functions that\ngarbage collect: `freeSym()`, `freeSymtable()`, `freeASTnode()` and\n`freetree()`.\n\nThat hasn't solved all the garbage collection issues. I've recently\nresorted to using [Valgrind](https://valgrind.org/) to show me where\nI have memory leaks. I try to find the worst cases and then work out\nwhere I can insert a `free()` that helps. This has got the compiler\nto the point where it _can_ self-compile on the 6809, but there is\ndefinitely room for improvement!\n\n## The Peephole Optimiser\n\nThe peephole optimiser, [cpeep.c](cpeep.c) was originally written\nby Christian W. Fraser in 1984. Looking at the [documentation](docs/copt.1),\nit has been worked on by several people since then. I imported it from the\n[Fuzix Compiler Kit](https://github.com/EtchedPixels/Fuzix-Compiler-Kit)\nand changed its name. I also changed the rule termination to be\n`====` instead of a blank line; I find it easier to see where rules end.\n\nThe 6809 backend can spit out some bad code. The optimiser helps to\nget rid of some of it. Have a look at the [rules.6809](lib/6809/rules.6809)\nfile to see what the rules are; I think I've documented them well enough.\nThere is a [test file](tests/input.rules.6809) which I use to check that\nthe rules work OK.\n\n## Building and Running the Compiler - QBE\n\nTo build the compiler on a Linux box so that it outputs x68 code, you\nfirst need to download [QBE 1.2](https://c9x.me/compile/releases.html),\nbuild it and install the `qbe` binary somewhere on your `$PATH`.\n\nNext, you need to make the `/opt/wcc` directory and make it writable\nby yourself.\n\nNow you can `make; make install`, which will build the compiler and put\nthe executables into `/opt/wcc/bin`, the header files into ``/opt/wcc/include`\nand the 6809 libraries into ``/opt/wcc/lib/6809`.\n\nNow make sure that `/opt/wcc/bin/wcc` (the compiler front-end) is on your\n`$PATH`. I usually put a symlink to it into my private `bin` folder.\n\nFrom here, you can `make test` which goes into the `tests/` directory and\nruns all the tests that are in there.\n\n## Building and Running the Compiler - 6809\n\nThis is a bit complicated.\n\nFirstly, you need to download the\n[Fuzix Bintools](https://github.com/EtchedPixels/Fuzix-Bintools),\nand build at least the assembler `as6809` and the linker `ld6809`.\nNow install these somewhere on your `$PATH`.\n\nNext, download my [Fuzemsys](https://github.com/DoctorWkt/Fuzemsys)\nproject. This has a 6809 emulator which we need to run the 6809 binaries.\nGo into the `emulators/` directory and `make emu6809`. Once this is\nbuilt, install the emulator somewhere on your `$PATH`.\n\nIf you haven't already, make the `/opt/wcc` directory as before,\ncome back to this project and `make; make install` to install it.\nMake sure that `/opt/wcc/bin/wcc` (the compiler front-end) is on your `$PATH`.\n\nFrom here, you can `make 6test` which goes into the `tests/` directory and\nruns all the tests that are in there. This time, we build 6809 binaries\nand use the 6809 emulator to run them.\n\n## Doing The QBE Triple Test\n\nWith `qbe` installed and you have done a `make install; make test` to\ncheck that the compiler works, you can now do a `make triple`. This:\n\n - builds the compiler with your native compiler,\n - builds the compiler with itself into the `L1` directory,\n - builds the compiler with itself again into the `L2` directory, and\n - checksums the `L1` and `L2` executables to ensure they are identical:\n\n```\n0f14b990d9a48352c4d883cd550720b3  L1/detok\n0f14b990d9a48352c4d883cd550720b3  L2/detok\n3cc59102c6a5dcc1661b3ab3dcce5191  L1/cgenqbe\n3cc59102c6a5dcc1661b3ab3dcce5191  L2/cgenqbe\n3e036c748bdb5e3ffc0e03506ed00243  L2/wcc      <-- different\n6fa26e506a597c9d9cfde7d168ae4640  L1/detree\n6fa26e506a597c9d9cfde7d168ae4640  L2/detree\n7f8e55a544400ab799f2357ee9cc4b44  L1/cscan\n7f8e55a544400ab799f2357ee9cc4b44  L2/cscan\n912ebc765c27a064226e9743eea3dd30  L1/wcc      <-- different\n9c6a66e8b8bbc2d436266c5a3ca622c7  L1/cparseqbe\n9c6a66e8b8bbc2d436266c5a3ca622c7  L2/cparseqbe\ncb493abe1feed812fb4bb5c958a8cf83  L1/desym\ncb493abe1feed812fb4bb5c958a8cf83  L2/desym\n```\n\nThe `wcc` binaries are different as one has `L1` in the path to find\nthe executables for the phases, and the other has `L2` instead.\n\n## Doing The 6809 Triple Test\n\nInstead of using the `Makefile` to do this, I have a separate Bash shell\nscript called `6809triple_test`. Run this to:\n\n - build the compiler with your native compiler,\n - build the 6809 compiler with itself into the `L1` directory, and\n - build the 6809 compiler with itself again into the `L2` directory.\n\nThis is slow! On my decent laptop it takes about 45 minutes. Eventually\nyou can do your own checksums to verify that the executables are identical:\n\n```\n$ md5sum L1/_* L2/_* | sort\n01c5120e56cb299bf0063a07e38ec2b9  L1/_cgen6809\n01c5120e56cb299bf0063a07e38ec2b9  L2/_cgen6809\n0caee9118cb7745eaf40970677897dbf  L1/_detree\n0caee9118cb7745eaf40970677897dbf  L2/_detree\n2d333482ad8b4a886b5b78a4a49f3bb5  L1/_detok\n2d333482ad8b4a886b5b78a4a49f3bb5  L2/_detok\nd507bd89c0fc1439efe2dffc5d8edfe3  L1/_desym\nd507bd89c0fc1439efe2dffc5d8edfe3  L2/_desym\ne78da1f3003d87ca852f682adc4214e8  L1/_cscan\ne78da1f3003d87ca852f682adc4214e8  L2/_cscan\ne9c8b2c12ea5bd4f62091fafaae45971  L1/_cparse6809\ne9c8b2c12ea5bd4f62091fafaae45971  L2/_cparse6809\n```\n\nAt the moment I'm having problems with running `wcc` as a 6809 executable,\nso I use the x64 `wcc` binary instead.\n\n## Example Command-line Actions\n\nHere is a capture of the commands I used to do all the above:\n\n```\n# Download the acwj repository\ncd /usr/local/src\ngit clone https://github.com/DoctorWkt/acwj\n\n# Make the destination directory\nsudo mkdir /opt/wcc\nsudo chown wkt:wkt /opt/wcc\n\n# Install QBE\ncd /usr/local/src\nwget https://c9x.me/compile/release/qbe-1.2.tar.xz\nxz -d qbe-1.2.tar.xz \ntar vxf qbe-1.2.tar \ncd qbe-1.2/\nmake\nsudo make install\n\n# Install the wcc compiler\ncd /usr/local/src/acwj/64_6809_Target\nmake install\n\n# Put wcc on my $PATH\ncd ~/.bin\nln -s /opt/wcc/bin/wcc .\n\n# Do the triple test on x64 using QBE\ncd /usr/local/src/acwj/64_6809_Target\nmake triple\n\n# Get the Fuzix-Bintools and build\n# the 6809 assembler and linker\ncd /usr/local/src\ngit clone https://github.com/EtchedPixels/Fuzix-Bintools\ncd Fuzix-Bintools/\nmake as6809 ld6809\ncp as6809 ld6809 ~/.bin\n\n# Get Fuzemsys and build the 6809 emulator.\n# I needed to install the readline library.\nsudo apt-get install libreadline-dev\ncd /usr/local/src\ngit clone https://github.com/DoctorWkt/Fuzemsys\ncd Fuzemsys/emulators/\nmake emu6809\ncp emu6809 ~/.bin\n\n# Go back to the compiler and do the\n# triple test using the 6809 emulator\ncd /usr/local/src/acwj/64_6809_Target\n./6809triple_test \n```\n\n## Is This Self-Compiling?\n\nWe can pass the triple test with the 6809 CPU. But, is this really\nself-compiling? Well, it is, but it is definitely _not_ self-hosting.\n\nThe things that this C compiler _doesn't_ build include:\n\n - a C pre-processor\n - the peephole optimiser\n - the 6809 assembler\n - the 6809 linker\n - an `ar` archiver for the 6809\n - the compiler helper functions, and the C library. At the moment,\n   I'm using the Fuzix Compiler Kit to build these functions. The\n   Fuzix Compiler speaks \"real\" C; this compiler only speaks a subset\n   of the C language, so it can't build these functions.\n\nSo, if I wanted to move all of this over to my\n[MMU09 SBC](https://github.com/DoctorWkt/MMU09), then I would need to\nuse the Fuzix Compiler to build the assembler, linker, helper functions\nand the C library.\n\nThus, the \"acwj\" compiler can definitely take pre-processed C source code\nand, using a scanner, a parser and a code generator, output 6809 assembly\ncode. And the \"acwj\" compiler can do the above on its own code.\n\nThat makes our compiler a self-compiling compiler, but not a self-hosting\ncompiler!\n\n## Future Work\n\nRight now, this isn't a production compiler. It's not even a proper C\ncompiler - it only knows a subset of the C language.\n\nSome things to do would be:\n\n - make it more robust\n - get on top of the garbage collection\n - add unsigned types\n - add floats and doubles\n - add more of the real C language to become self-hosting\n - improve the quality of the 6809 code generator\n - improve the speed of the 6809 compiler\n - perhaps, take a big step back, use the lessons\n   learned through this whole journey and rewrite\n   a new compiler from scratch!\n\n## Conclusion\n\nI'm pretty burned out after this part - it's taken a few months of\nwork as evidenced by my [notes](docs/NOTES.md). And we are now up\nto part 64 of the \"acwj\" journey; that's a good power of two :-)\n\nSo I won't say definitely not, but I think this is where I'll end the\n\"acwj\" journey. If you have followed along through some/most/all of\nthe parts, then thank you for spending the time reading my notes.\nI hope it's been useful.\n\nAnd, now, if you need a sort-of C compiler for an 8-bit or 16-bit\nCPU with a limited set of registers, this might be a starting point for you!\n\nCheers, Warren\n"
  },
  {
    "path": "64_6809_Target/cg.h",
    "content": "/* cg.c */\nvoid cgtextseg();\nvoid cgdataseg();\nvoid cglitseg();\nvoid cgfreeallregs(int keepreg);\nint cgallocreg(int type);\nvoid cgfreereg(int reg);\nvoid cgspillregs();\nvoid cgpreamble();\nvoid cgpostamble();\nvoid cgfuncpreamble(struct symtable *sym);\nvoid cgfuncpostamble(struct symtable *sym);\nint cgloadint(int value, int type);\nint cgloadvar(struct symtable *sym, int op);\nint cgloadglobstr(int label);\nint cgadd(int r1, int r2, int type);\nint cgsub(int r1, int r2, int type);\nint cgmul(int r1, int r2, int type);\nint cgdiv(int r1, int r2, int type);\nint cgmod(int r1, int r2, int type);\nint cgand(int r1, int r2, int type);\nint cgor(int r1, int r2, int type);\nint cgxor(int r1, int r2, int type);\nint cginvert(int r, int type);\nint cgshl(int r1, int r2, int type);\nint cgshr(int r1, int r2, int type);\nint cgnegate(int r, int type);\nint cglognot(int r, int type);\nint cgloadboolean(int r, int val, int type);\nint cgboolean(int r, int op, int label, int type);\nint cgcall(struct symtable *sym, int numargs, int *arglist, int *typelist);\nint cgshlconst(int r, int val, int type);\nint cgstorglob(int r, struct symtable *sym);\nint cgstorlocal(int r, struct symtable *sym);\nvoid cgglobsym(struct symtable *node);\nvoid cgglobstr(int l, char *strvalue);\nint cgcompare_and_set(int ASTop, int r1, int r2, int type);\nvoid cglabel(int l);\nvoid cgjump(int l);\nint cgcompare_and_jump(int ASTop, int parentASTop,\n\t\t\t\tint r1, int r2, int label, int type);\nint cgcast(int t, int oldtype, int newtype);\nint cgwiden(int r, int oldtype, int newtype);\nvoid cgreturn(int r, struct symtable *sym);\nint cgaddress(struct symtable *sym);\nint cgderef(int r, int type);\nint cgstorderef(int r1, int r2, int type);\nvoid cgswitch(int reg, int casecount, int toplabel, int *caselabel, int *caseval, int defaultlabel);\nvoid cgmove(int r1, int r2, int type);\nvoid cglinenum(int line);\n"
  },
  {
    "path": "64_6809_Target/cg6809.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"gen.h\"\n#include \"misc.h\"\n#include \"types.h\"\n#include \"target.h\"\n\n// Code generator for 6809\n// Copyright (c) 2024 Warren Toomey, GPL3\n\n// Instead of registers, we keep a list of locations.\n// They can be one of the following:\n\nenum {\n  L_FREE,\t\t// This location is not used\n  L_SYMBOL,\t\t// A global symbol with an optional offset\n  L_LOCAL,\t\t// A local variable or parameter\n  L_CONST,\t\t// An integer literal value\n  L_LABEL,\t\t// A label\n  L_SYMADDR,\t\t// The address of a symbol, local or parameter\n  L_TEMP,\t\t// A temporarily-stored value\n  L_DREG\t\t// The D location, i.e. B, D or Y/D\n};\n\nstruct Location {\n  int type;\t\t// One of the L_ values\n  char *name;\t\t// A symbol's name\n  long intval;\t\t// Offset, const value, label-id etc.\n  int primtype;\t\t// 6809 primiive type, see PR_POINTER below\n};\n\n// We also track if D holds a copy of a location.\n// It could be NOREG if it is available.\nstatic int d_holds;\n\n#define NUMFREELOCNS 16\nstatic struct Location Locn[NUMFREELOCNS];\n\n// We also need a set of temporary locations in memory.\n// They are defined in crt0.s as R0, R1 etc.\n// They can be allocated incrementally.\nstatic int next_free_temp;\n\n// Allocate a currently free temporary location\nstatic int cgalloctemp() {\n  return(next_free_temp++);\n}\n\n// Free all temporary locations\nstatic void cgfreealltemps() {\n  next_free_temp=0;\n}\n\n// Parameters and local variables live\n// on the stack. We need to adjust their offset\n// each time we push/pop off the stack. sp_adjust\n// holds the number of extra bytes on the stack.\nstatic int sp_adjust;\n\n// We convert C types to types on the 6809:\n// PR_CHAR, PR_INT, PR_LONG, PR_POINTER.\n#define PR_CHAR\t\t1\n#define PR_INT\t\t2\n#define PR_POINTER\t3\n#define PR_LONG\t\t4\n\n// Given a C type, return the matching 6809 type\nstatic int cgprimtype(int type) {\n  if (ptrtype(type))  return(PR_POINTER);\n  if (type == P_CHAR) return(PR_CHAR);\n  if (type == P_INT)  return(PR_INT);\n  if (type == P_LONG) return(PR_LONG);\n  fatald(\"Bad type in cgprimtype:\", type);\n  return(0);\t\t// Keep -Wall happy\n}\n\n// Print a location out. For memory locations\n// use the offset. For constants, use the\n// register letter to determine which part to use.\nstatic void printlocation(int l, int offset, char rletter) {\n  int intval;\n\n  if (Locn[l].type == L_FREE)\n    fatald(\"Error trying to print location\", l);\n\n  switch(Locn[l].type) {\n    case L_SYMBOL: fprintf(Outfile, \"_%s+%d\\n\", Locn[l].name, offset); break;\n    case L_LOCAL: fprintf(Outfile, \"%ld,s\\n\",\n\t\tLocn[l].intval + offset + sp_adjust);\n\tbreak;\n    case L_LABEL: fprintf(Outfile, \"#L%ld\\n\", Locn[l].intval); break;\n    case L_SYMADDR: fprintf(Outfile, \"#_%s\\n\", Locn[l].name); break;\n    case L_TEMP: fprintf(Outfile, \"R%ld+%d\\n\", Locn[l].intval, offset);\n\tbreak;\n    case L_CONST:\n      // We convert Locn[l].intval (a long) to intval (an int). If\n      // we did, for example, Locn[l].intval & 0xffff, on the 6809\n      // the 0xffff gets widened to 32 bits. But this is a negative\n      // value, so it gets widened to 0xffffffff not 0x0000ffff.\n      switch(rletter) {\n\tcase 'b':\n\t  fprintf(Outfile, \"#%ld\\n\", Locn[l].intval & 0xff); break;\n\tcase 'a':\n\t  fprintf(Outfile, \"#%ld\\n\", (Locn[l].intval >> 8) & 0xff); break;\n\tcase 'd':\n\t  intval= (int)Locn[l].intval;\n\t  fprintf(Outfile, \"#%d\\n\", intval & 0xffff); break;\n\tcase 'y':\n\t  intval= (int)(Locn[l].intval >> 16);\n\t  fprintf(Outfile, \"#%d\\n\", intval & 0xffff); break;\n\n\t// These are the top two bytes of a 32-bit value\n\tcase 'f':\n\t  fprintf(Outfile, \"#%ld\\n\", (Locn[l].intval >> 16) & 0xff); break;\n\tcase 'e':\n\t  fprintf(Outfile, \"#%ld\\n\", (Locn[l].intval >> 24) & 0xff); break;\n      }\n      break;\n    default: fatald(\"Unknown type for location\", l);\n  }\n}\n\n// Save D (B, D, Y/D) to a location.\nstatic void save_d(int l) {\n\n  // If we are saving to ourself then\n  // there is nothing to do :-)\n  if (Locn[l].type == L_DREG) return;\n\n  switch (Locn[l].primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\tstb \"); printlocation(l, 0, 'b');\n      break;\n    case PR_INT:\n    case PR_POINTER:\n      fprintf(Outfile, \"\\tstd \"); printlocation(l, 0, 'd');\n      break;\n    case PR_LONG:\n      fprintf(Outfile, \"\\tstd \"); printlocation(l, 2, 'd');\n      fprintf(Outfile, \"\\tsty \"); printlocation(l, 0, 'y');\n  }\n  d_holds= l;\n}\n\n// Stash D in a temporary if required\nstatic void stash_d() {\n  // If D holds a value, we will need to store it\n  // in a temporary location\n  if (d_holds != NOREG && Locn[d_holds].type == L_DREG) {\n    Locn[d_holds].type= L_TEMP;\n    Locn[d_holds].intval= cgalloctemp();\n    save_d(d_holds);\n  }\n}\n\n// Load D (B, D, Y/D) with a location.\nstatic void load_d(int l) {\n  // If l is already L_DREG, do nothing.\n  if (Locn[l].type== L_DREG) return;\n\n  // If D holds a value, we will need to store it\n  // in a temporary location\n  stash_d();\n\n  // Load the existing location into D and mark it as L_DREG.\n  switch(Locn[l].primtype) {\n    case PR_CHAR:\n\tfprintf(Outfile, \"\\tldb \"); printlocation(l, 0, 'b'); break;\n    case PR_INT:\n    case PR_POINTER:\n\tfprintf(Outfile, \"\\tldd \"); printlocation(l, 0, 'd'); break;\n    case PR_LONG:\n\tfprintf(Outfile, \"\\tldd \"); printlocation(l, 2, 'd');\n\tfprintf(Outfile, \"\\tldy \"); printlocation(l, 0, 'y');\n  }\n\n  Locn[l].type= L_DREG;\n  d_holds= l;\n}\n\n// Set all locations as available.\n// If keepl is positive, don't free that one.\nstatic void cgfreeall_locns(int keepl) {\n  int l;\n\n  for (l = 0; l < NUMFREELOCNS; l++)\n    if (l != keepl) {\n      Locn[l].type= L_FREE;\n    }\n\n  if (keepl == NOREG)\n    cgfreealltemps();\n  fprintf(Outfile, \";\\n\");\n  d_holds= NOREG;\n}\n\n// Allocate a free location. Return the number of\n// the location. Die if no available locations.\nstatic int cgalloclocn(int type, int primtype, char *name, long intval) {\n  int l;\n\n  for (l = 0; l < NUMFREELOCNS; l++) {\n    if (Locn[l].type== L_FREE) {\n\n      // If we're asked for a temporary, get one\n      if (type==L_TEMP)\n\tintval= cgalloctemp();\n      if (type==L_DREG)\n\td_holds= l;\n      Locn[l].type= type;\n      Locn[l].primtype= primtype;\n      Locn[l].name= name;\n      Locn[l].intval= intval;\n      return(l);\n    }\n  }\n\n  fatal(\"Out of locations in cgalloclocn\");\n  return(0);\t// Keep -Wall happy\n}\n\n// Free a location. Check to see if it's not already there.\nstatic void cgfreelocn(int l) {\n  if (Locn[l].type== L_FREE)\n    fatald(\"Error trying to free location\", l);\n  Locn[l].type= L_FREE;\n  if (d_holds ==l) d_holds= NOREG;\n}\n\n// gen.c calls us as if we have registers\nvoid cgfreeallregs(int keepl) {\n  cgfreeall_locns(keepl);\n}\n\nint cgallocreg(int type) {\n  return(cgalloclocn(L_TEMP, cgprimtype(type), NULL, 0));\n}\n\nvoid cgfreereg(int reg) {\n  cgfreelocn(reg);\n}\n\n// Push a location on the stack\nstatic void pushlocn(int l) {\n  load_d(l);\n\n  switch(Locn[l].primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\tpshs b\\n\");\n      sp_adjust += 1;\n      break;\n    case PR_INT:\n    case PR_POINTER:\n      fprintf(Outfile, \"\\tpshs d\\n\");\n      sp_adjust += 2;\n      break;\n    case PR_LONG:\n      fprintf(Outfile, \"\\tpshs d\\n\");\n      fprintf(Outfile, \"\\tpshs y\\n\");\n      sp_adjust += 4;\n  }\n\n  cgfreelocn(l);\n  d_holds= NOREG;\n}\n\n// Flag to say which section were are outputting in to\nenum { no_seg, text_seg, data_seg, lit_seg } currSeg = no_seg;\n\n// Switch to the text segment\nvoid cgtextseg() {\n  if (currSeg != text_seg) {\n    fputs(\"\\t.code\\n\", Outfile);\n    currSeg = text_seg;\n  }\n}\n\n// Switch to the data segment\nvoid cgdataseg() {\n  if (currSeg != data_seg) {\n    fputs(\"\\t.data\\n\", Outfile);\n    currSeg = data_seg;\n  }\n}\n\n// Switch to the literal segment\nvoid cglitseg() {\n  if (currSeg != lit_seg) {\n    fputs(\"\\t.literal\\n\", Outfile);\n    currSeg = lit_seg;\n  }\n}\n\n// Position of next local variable relative to stack base pointer.\n// We store the offset as positive to make aligning the stack pointer easier\nstatic int localOffset;\n\n// Create the position of a new local variable.\nstatic int newlocaloffset(int size) {\n  int o;\n\n  // Return the current localOffset and\n  // then increment the localOffset\n  o= localOffset;\n  localOffset += size;\n  return (o);\n}\n\n\n// Print out the assembly preamble\n// for one output file\nvoid cgpreamble() {\n  cgfreeall_locns(NOREG);\n  cgfreealltemps();\n  cgtextseg();\n}\n\n// Nothing to do for the end of a file\nvoid cgpostamble() {\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"L%d:\\n\", l);\n}\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int paramOffset = 2;\t// Any pushed params start at this frame offset\n\n  // Output in the text segment, reset local offset\n  // and the amount of args on the stack\n  cgtextseg();\n  localOffset = 0;\n  next_free_temp = 0;\n  sp_adjust = 0;\n\n  // Output the function start\n  if (sym->class == V_GLOBAL) {\n    fprintf(Outfile, \"\\t.export _%s\\n\", name);\n  }\n  fprintf(Outfile, \"_%s:\\n\", name);\n\n  // Make frame positions for the locals.\n  // Skip over the parameters in the member list first\n  for (locvar = sym->member; locvar != NULL; locvar = locvar->next)\n    if (locvar->class==V_LOCAL) break;\n\n  for (; locvar != NULL; locvar = locvar->next) {\n    locvar->st_posn = newlocaloffset(locvar->size);\n    // fprintf(Oufile, \"; placed local %s size %d at offset %d\\n\",\n    //\t\t\tlocvar->name, locvar->size, locvar->st_posn);\n  }\n\n  // Work out the frame offset for the parameters.\n  // Do this once we know the total size of the locals.\n  // Stop once we hit the locals\n  for (parm = sym->member; parm != NULL; parm = parm->next) {\n    if (parm->class==V_LOCAL) break;\n    parm->st_posn = paramOffset + localOffset;\n    paramOffset += parm->size;\n    // fprintf(Outfile, \"; placed param %s size %d at offset %d\\n\",\n    // \t\t\t\tparm->name, parm->size, parm->st_posn);\n  }\n\n  // Bring the stack down to below the locals\n  if (localOffset!=0)\n    fprintf(Outfile, \"\\tleas -%d,s\\n\", localOffset);\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n  if (localOffset!=0)\n    fprintf(Outfile, \"\\tleas %d,s\\n\", localOffset);\n  fputs(\"\\trts\\n\", Outfile);\n  cgfreeall_locns(NOREG);\n  cgfreealltemps();\n\n  if (sp_adjust !=0 ) {\n    fprintf(Outfile, \"; DANGER sp_adjust is %d not 0\\n\", sp_adjust);\n    fatald(\"sp_adjust is not zero\", sp_adjust);\n  }\n}\n\n// Load an integer literal value into a location.\n// Return the number of the location.\nint cgloadint(int value, int type) {\n  int primtype= cgprimtype(type);\n  return(cgalloclocn(L_CONST, primtype, NULL, value));\n}\n\n// Increment the value at a symbol by offset\n// which could be positive or negative\nstatic void incdecsym(struct symtable *sym, int offset) {\n    // Load the symbol's address\n    if (sym->class == V_LOCAL || sym->class == V_PARAM)\n      fprintf(Outfile, \"\\tleax %d,s\\n\", sym->st_posn + sp_adjust);\n    else\n      fprintf(Outfile, \"\\tldx #_%s\\n\", sym->name);\n\n    // Now change the value at that address\n    switch (sym->size) {\n    case 1:\n      fprintf(Outfile, \"\\tldb #%d\\n\", offset & 0xff);\n      fprintf(Outfile, \"\\taddb 0,x\\n\");\n      fprintf(Outfile, \"\\tstb 0,x\\n\");\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tldd #%d\\n\", offset & 0xffff);\n      fprintf(Outfile, \"\\taddd 0,x\\n\");\n      fprintf(Outfile, \"\\tstd 0,x\\n\");\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tldd #%d\\n\", offset);\n      fprintf(Outfile, \"\\taddd 2,x\\n\");\n      fprintf(Outfile, \"\\tstd 2,x\\n\");\n      fprintf(Outfile, \"\\tldd 0,x\\n\");\n      fprintf(Outfile, \"\\tadcb #0\\n\");\n      fprintf(Outfile, \"\\tadca #0\\n\");\n      fprintf(Outfile, \"\\tstb 0,x\\n\");\n    }\n}\n\n// Load a value from a variable into a location.\n// Return the number of the location. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadvar(struct symtable *sym, int op) {\n  int l, offset = 1;\n  int primtype= cgprimtype(sym->type);\n\n  // If the symbol is a pointer, use the size\n  // of the type that it points to as any\n  // increment or decrement. If not, it's one.\n  if (ptrtype(sym->type))\n    offset = typesize(value_at(sym->type), sym->ctype);\n\n  // Negate the offset for decrements\n  if (op == A_PREDEC || op == A_POSTDEC)\n    offset = -offset;\n\n  // If we have a pre-operation, do it\n  if (op == A_PREINC || op == A_PREDEC)\n    incdecsym(sym, offset);\n\n  // Get a new location and set it up\n  if (sym->class == V_LOCAL || sym->class == V_PARAM)\n    l= cgalloclocn(L_LOCAL, primtype, NULL, sym->st_posn + sp_adjust);\n  else\n    l= cgalloclocn(L_SYMBOL, primtype, sym->name, 0);\n\n  // If we have a post-operation, do it\n  // but get the current value into a temporary.\n  if (op == A_POSTINC || op == A_POSTDEC) {\n    load_d(l);\n    stash_d();\n    incdecsym(sym, offset);\n    load_d(l);\n  }\n\n  // Return the location with the value\n  return (l);\n}\n\n// Given the label number of a global string,\n// load its address into a new location\nint cgloadglobstr(int label) {\n  // Get a new location\n  int l = cgalloclocn(L_LABEL, PR_INT, NULL, label);\n  return (l);\n}\n\n// Add two locations together and return\n// the number of the location with the result\nint cgadd(int l1, int l2, int type) {\n  int primtype= cgprimtype(type);\n\n  load_d(l1);\n\n  switch(primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\taddb \"); printlocation(l2, 0, 'b'); break;\n    case PR_INT:\n    case PR_POINTER:\n      fprintf(Outfile, \"\\taddd \"); printlocation(l2, 0, 'd'); break;\n      break;\n    case PR_LONG:\n      fprintf(Outfile, \"\\taddd \"); printlocation(l2, 2, 'd');\n      fprintf(Outfile, \"\\texg y,d\\n\");\n      fprintf(Outfile, \"\\tadcb \"); printlocation(l2, 1, 'f');\n      fprintf(Outfile, \"\\tadca \"); printlocation(l2, 0, 'e');\n      fprintf(Outfile, \"\\texg y,d\\n\");\n  }\n  cgfreelocn(l2);\n  Locn[l1].type= L_DREG;\n  d_holds= l1;\n  return(l1);\n}\n\n// Subtract the second location from the first and\n// return the number of the location with the result\nint cgsub(int l1, int l2, int type) {\n  int primtype= cgprimtype(type);\n\n  load_d(l1);\n\n  switch(primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\tsubb \"); printlocation(l2, 0, 'b'); break;\n      break;\n    case PR_INT:\n    case PR_POINTER:\n      fprintf(Outfile, \"\\tsubd \"); printlocation(l2, 0, 'd'); break;\n      break;\n    case PR_LONG:\n      fprintf(Outfile, \"\\tsubd \"); printlocation(l2, 2, 'd');\n      fprintf(Outfile, \"\\texg y,d\\n\");\n      fprintf(Outfile, \"\\tsbcb \"); printlocation(l2, 1, 'f');\n      fprintf(Outfile, \"\\tsbca \"); printlocation(l2, 0, 'e');\n      fprintf(Outfile, \"\\texg y,d\\n\");\n  }\n  cgfreelocn(l2);\n  Locn[l1].type= L_DREG;\n  d_holds= l1;\n  return (l1);\n}\n\n// Run a helper subroutine on two locations\n// and return the number of the location with the result\nstatic int cgbinhelper(int l1, int l2, int type,\n\t\t\t\tchar *cop, char *iop, char *lop) {\n  int primtype= cgprimtype(type);\n\n  load_d(l1);\n\n  switch(primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\tclra\\n\");\n      fprintf(Outfile, \"\\tpshs d\\n\");\n      sp_adjust += 2;\n      fprintf(Outfile, \"\\tldb \"); printlocation(l2, 0, 'b');\n      fprintf(Outfile, \"\\tlbsr %s\\n\", cop);\n      sp_adjust -= 2;\n      break;\n    case PR_INT:\n    case PR_POINTER:\n      fprintf(Outfile, \"\\tpshs d\\n\");\n      sp_adjust += 2;\n      fprintf(Outfile, \"\\tldd \"); printlocation(l2, 0, 'd');\n      fprintf(Outfile, \"\\tlbsr %s\\n\", iop);\n      sp_adjust -= 2;\n      break;\n    case PR_LONG:\n      fprintf(Outfile, \"\\tpshs d\\n\");\n      fprintf(Outfile, \"\\tpshs y\\n\");\n      sp_adjust += 4;\n      fprintf(Outfile, \"\\tldy \"); printlocation(l2, 0, 'd');\n      fprintf(Outfile, \"\\tldd \"); printlocation(l2, 2, 'y');\n      fprintf(Outfile, \"\\tlbsr %s\\n\", lop);\n      sp_adjust -= 4;\n  }\n  cgfreelocn(l2);\n  Locn[l1].type= L_DREG;\n  d_holds= l1;\n  return (l1);\n}\n\n// Multiply two locations together and return\n// the number of the location with the result\nint cgmul(int r1, int r2, int type) {\n  return(cgbinhelper(r1, r2, type, \"__mul\", \"__mul\", \"__mull\"));\n}\n\n// Divide the first location by the second and\n// return the number of the location with the result\nint cgdiv(int r1, int r2, int type) {\n  return(cgbinhelper(r1, r2, type, \"__div\", \"__div\", \"__divl\"));\n}\n\n// Divide the first location by the second to get\n// the remainder. Return the number of the location with the result\nint cgmod(int r1, int r2, int type) {\n  return(cgbinhelper(r1, r2, type, \"__rem\", \"__rem\", \"__reml\"));\n}\n\n// Generic binary operation on two locations\nstatic int cgbinop(int l1, int l2, int type, char *op) {\n  int primtype= cgprimtype(type);\n\n  load_d(l1);\n\n  switch(primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\t%sb \", op); printlocation(l2, 0, 'b');\n      break;\n    case PR_INT:\n    case PR_POINTER:\n      fprintf(Outfile, \"\\t%sa \", op); printlocation(l2, 0, 'a');\n      fprintf(Outfile, \"\\t%sb \", op); printlocation(l2, 1, 'b');\n      break;\n    case PR_LONG:\n      fprintf(Outfile, \"\\t%sa \", op); printlocation(l2, 2, 'a');\n      fprintf(Outfile, \"\\t%sb \", op); printlocation(l2, 3, 'b');\n      fprintf(Outfile, \"\\texg y,d\\n\");\n      fprintf(Outfile, \"\\t%sa \", op); printlocation(l2, 0, 'e');\n      fprintf(Outfile, \"\\t%sb \", op); printlocation(l2, 1, 'f');\n      fprintf(Outfile, \"\\texg y,d\\n\");\n      break;\n  }\n  cgfreelocn(l2);\n  Locn[l1].type= L_DREG;\n  d_holds= l1;\n  return (l1);\n}\n\n// Bitwise AND two locations\nint cgand(int r1, int r2, int type) {\n  return(cgbinop(r1, r2, type, \"and\"));\n}\n\n// Bitwise OR two locations\nint cgor(int r1, int r2, int type) {\n  return(cgbinop(r1, r2, type, \"or\"));\n}\n\n// Bitwise XOR two locations\nint cgxor(int r1, int r2, int type) {\n  return(cgbinop(r1, r2, type, \"eor\"));\n}\n\n// Invert a location's value\nint cginvert(int l, int type) {\n  int primtype= cgprimtype(type);\n\n  load_d(l);\n\n  switch(primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\tcomb\\n\");\n    case PR_INT:\n    case PR_POINTER:\n      fprintf(Outfile, \"\\tcoma\\n\");\n      fprintf(Outfile, \"\\tcomb\\n\");\n      break;\n    case PR_LONG:\n      fprintf(Outfile, \"\\tcoma\\n\");\n      fprintf(Outfile, \"\\tcomb\\n\");\n      fprintf(Outfile, \"\\texg y,d\\n\");\n      fprintf(Outfile, \"\\tcoma\\n\");\n      fprintf(Outfile, \"\\tcomb\\n\");\n      fprintf(Outfile, \"\\texg y,d\\n\");\n  }\n\n  Locn[l].type= L_DREG;\n  d_holds= l;\n  return(l);\n}\n\n// Shift left r1 by r2 bits\nint cgshl(int r1, int r2, int type) {\n  return(cgbinhelper(r1, r2, type, \"__shl\", \"__shl\", \"__shll\"));\n}\n\n// Shift r1 right by 8, 16 or 24 bits\nint cgshrconst(int r1, int amount, int type) {\n  int primtype= cgprimtype(type);\n  int temp;\n\n  load_d(r1);\n\n  switch(primtype) {\n    // Any shift on B clears it\n    case PR_CHAR:\n      fprintf(Outfile, \"\\tclrb\\n\"); return(r1);\n    case PR_INT:\n    case PR_POINTER:\n      switch(amount) {\n\tcase  8:\n          fprintf(Outfile, \"\\ttfr a,b\\n\");\n          fprintf(Outfile, \"\\tclra\\n\"); return(r1);\n\tcase 16:\n\tcase 24:\n          fprintf(Outfile, \"\\tclra\\n\");\n          fprintf(Outfile, \"\\tclrb\\n\"); return(r1);\n      }\n    case PR_LONG:\n      switch(amount) {\n\tcase  8:\n          temp= cgalloctemp();\n\t  fprintf(Outfile, \"\\tclr R%d ; long >> 8\\n\", temp);\n\t  fprintf(Outfile, \"\\tsty R%d+1\\n\", temp);\n\t  fprintf(Outfile, \"\\tsta R%d+3\\n\", temp);\n\t  fprintf(Outfile, \"\\tldy R%d\\n\", temp);\n\t  fprintf(Outfile, \"\\tldd R%d+2\\n\", temp); return(r1);\n\tcase 16:\n          fprintf(Outfile, \"\\ttfr y,d ; long >> 16\\n\");\n\t  fprintf(Outfile, \"\\tldy #0\\n\"); return(r1);\n\tcase 24:\n          fprintf(Outfile, \"\\ttfr y,d ; long >> 24\\n\");\n          fprintf(Outfile, \"\\ttfr a,b\\n\");\n          fprintf(Outfile, \"\\tclra\\n\");\n\t  fprintf(Outfile, \"\\tldy #0\\n\"); return(r1);\n      }\n  }\n  return(0);\t// Keep -Wall happy\n}\n\n// Shift right r1 by r2 bits\nint cgshr(int r1, int r2, int type) {\n  int val;\n\n  // If r2 is the constant 8, 16 or 24\n  // we can do it with just a few instructions\n  if (Locn[r2].type== L_CONST) {\n    val= (int)Locn[r2].intval;\n    if (val==8 || val==16 || val==24)\n      return(cgshrconst(r1, val, type));\n  }\n\n  return(cgbinhelper(r1, r2, type, \"__shr\", \"__shr\", \"__shrl\"));\n}\n\n// Negate a location's value\nint cgnegate(int l, int type) {\n  int primtype= cgprimtype(type);\n\n  load_d(l);\n\n  switch(primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\tnegb\\n\");\n      break;\n    case PR_INT:\n    case PR_POINTER:\n      fprintf(Outfile, \"\\tcoma\\n\");\n      fprintf(Outfile, \"\\tcomb\\n\");\n      fprintf(Outfile, \"\\taddd #1\\n\");\n      break;\n    case PR_LONG:\n      fprintf(Outfile, \"\\tlbsr __negatel\\n\");\n  }\n  Locn[l].type= L_DREG;\n  d_holds= l;\n  return (l);\n}\n\n// Logically negate a location's value\nint cglognot(int l, int type) {\n  // Get two labels\n  int label1 = genlabel();\n  int label2 = genlabel();\n  int primtype= cgprimtype(type);\n\n  load_d(l);\n\n  switch(primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\tcmpb #0\\n\");\n      fprintf(Outfile, \"\\tbne L%d\\n\", label1);\n      fprintf(Outfile, \"\\tldd #1\\n\");\n      break;\n    case PR_INT:\n    case PR_POINTER:\n      fprintf(Outfile, \"\\tcmpd #0\\n\");\n      fprintf(Outfile, \"\\tbne L%d\\n\", label1);\n      fprintf(Outfile, \"\\tldd #1\\n\");\n      break;\n    case PR_LONG:\n      fprintf(Outfile, \"\\tcmpd #0\\n\");\n      fprintf(Outfile, \"\\tbne L%d\\n\", label1);\n      fprintf(Outfile, \"\\tcmpy #0\\n\");\n      fprintf(Outfile, \"\\tbne L%d\\n\", label1);\n      fprintf(Outfile, \"\\tldd #1\\n\");\n  }\n  fprintf(Outfile, \"\\tbra L%d\\n\", label2);\n  cglabel(label1);\n  fprintf(Outfile, \"\\tldd #0\\n\");\n  cglabel(label2);\n\n  Locn[l].type= L_DREG;\n  d_holds= l;\n  return (l);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given location. Allocate\n// a location if l is NOREG.\nint cgloadboolean(int l, int val, int type) {\n  int primtype= cgprimtype(type);\n  int templ;\n\n  // Put the value into a literal location.\n  // Load it into D.\n  templ= cgalloclocn(L_CONST, primtype, NULL, val);\n  load_d(templ);\n\n  // Return the literal location or\n  // save the value and return that location\n  if (l==NOREG) {\n    return(templ);\n  } else {\n    save_d(l);\n    return(l);\n  }\n  return(NOREG);\t// Keep -Wall happy\n}\n\n// Set the Z flag if D is already loaded. Otherwise,\n// load the D register which will set the Z flag\nstatic void load_d_z(int l, int type) {\n  int primtype= cgprimtype(type);\n  int label = genlabel();\n\n  if (Locn[l].type== L_DREG) {\n    switch(primtype) {\n      case PR_CHAR:\n        fprintf(Outfile, \"\\tcmpb #0\\n\");\n        break;\n      case PR_INT:\n      case PR_POINTER:\n        fprintf(Outfile, \"\\tcmpd #0\\n\");\n        break;\n      case PR_LONG:\n        fprintf(Outfile, \"\\tcmpd #0\\n\");\n        fprintf(Outfile, \"\\tbne L%d\\n\", label);\n        fprintf(Outfile, \"\\tcmpy #0\\n\");\n        cglabel(label);\n    }\n  } else\n    load_d(l);\n}\n\n// Convert an integer value to a boolean value for\n// a TOBOOL operation. Jump if true if it's an IF,\n// WHILE operation. Jump if false if it's\n// a LOGOR operation.\nint cgboolean(int l, int op, int label, int type) {\n  int primtype= cgprimtype(type);\n  char *jmpop= \"beq\";\n\n  if (op== A_LOGOR) jmpop= \"bne\";\n\n  load_d_z(l, type);\n\n  switch(primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\t%s L%d\\n\", jmpop, label);\n      break;\n    case PR_INT:\n    case PR_POINTER:\n      fprintf(Outfile, \"\\t%s L%d\\n\", jmpop, label);\n      break;\n    case PR_LONG:\n      fprintf(Outfile, \"\\tpshs y\\n\");\n      fprintf(Outfile, \"\\tora 0,s\\n\");\n      fprintf(Outfile, \"\\torb 1,s\\n\");\n      fprintf(Outfile, \"\\tleas 2,s\\n\");\n      fprintf(Outfile, \"\\t%s L%d\\n\", jmpop, label);\n  }\n\n  // If the op is A_TOBOOL, set the location to 1\n  if (op == A_TOBOOL) {\n    cgloadboolean(l, 1, type);\n    return(l);\n  }\n  return(NOREG);\n}\n\n// Call a function with the given symbol id.\n// Beforehand, push the arguments on the stack.\n// Afterwards, pop off any arguments pushed on the stack.\n// Return the location with the result.\nint cgcall(struct symtable *sym, int numargs, int *arglist, int *typelist) {\n  int i, l, argamount;\n  int gentype= sym->type;\n  int primtype= 0;\n\n  // If it's not a void function, get its primtype.\n  // Also stash any D value in a temporary.\n  if (gentype!=P_VOID) {\n    stash_d();\n    primtype= cgprimtype(sym->type);\n  }\n\n  // Push the function arguments on the stack\n  argamount=0;\n  for (i= 0; i< numargs; i++) {\n    pushlocn(arglist[i]);\n    argamount += cgprimsize(typelist[i]);\n  }\n\n  // Call the function, adjust the stack\n  fprintf(Outfile, \"\\tlbsr _%s\\n\", sym->name);\n  fprintf(Outfile, \"\\tleas %d,s\\n\", argamount);\n  sp_adjust -= argamount;\n\n  // If it's not a void function, mark the result in D\n  if (gentype!=P_VOID) {\n    // Get a location and say that D is in use\n    l = cgalloclocn(L_DREG, primtype, NULL, 0);\n    return (l);\n  }\n  return(NOREG);\n}\n\n// Shift a location left by a constant, only 1 or 2\nint cgshlconst(int l, int val, int type) {\n  int primtype= cgprimtype(type);\n\n  load_d(l);\n\n  switch(primtype) {\n    case PR_CHAR:\n      if (val==2) {\n        fprintf(Outfile, \"\\taslb\\n\");\n      }\n      fprintf(Outfile, \"\\taslb\\n\");\n      break;\n    case PR_INT:\n    case PR_POINTER:\n      if (val==2) {\n        fprintf(Outfile, \"\\taslb\\n\");\n        fprintf(Outfile, \"\\trola\\n\");\n      }\n      fprintf(Outfile, \"\\taslb\\n\");\n      fprintf(Outfile, \"\\trola\\n\");\n      break;\n    case PR_LONG:\n      if (val==2) {\n        fprintf(Outfile, \"\\taslb\\n\");\n        fprintf(Outfile, \"\\trola\\n\");\n      }\n      fprintf(Outfile, \"\\texg y,d\\n\");\n      fprintf(Outfile, \"\\trolb\\n\");\n      fprintf(Outfile, \"\\trola\\n\");\n      fprintf(Outfile, \"\\texg y,d\\n\");\n  }\n  Locn[l].type= L_DREG;\n  d_holds= l;\n  return (l);\n}\n\n// Store a location's value into a variable\nint cgstorglob(int l, struct symtable *sym) {\n  int size= cgprimsize(sym->type);\n\n  load_d(l);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\tstb _%s\\n\", sym->name);\n      break;\n    case 2:\n      fprintf(Outfile, \"\\tstd _%s\\n\", sym->name);\n      break;\n    case 4:\n      fprintf(Outfile, \"\\tstd _%s+2\\n\", sym->name);\n      fprintf(Outfile, \"\\tsty _%s\\n\", sym->name);\n  }\n  return (l);\n}\n\n// Store a location's value into a local variable\nint cgstorlocal(int l, struct symtable *sym) {\n  int primtype= cgprimtype(sym->type);\n\n  load_d(l);\n\n  switch (primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\tstb %d,s\\n\", sym->st_posn + sp_adjust);\n      break;\n    case PR_INT:\n    case PR_POINTER:\n      fprintf(Outfile, \"\\tstd %d,s\\n\", sym->st_posn + sp_adjust);\n      break;\n    case PR_LONG:\n      fprintf(Outfile, \"\\tsty %d,s\\n\", sym->st_posn + sp_adjust);\n      fprintf(Outfile, \"\\tstd %d,s\\n\", 2+sym->st_posn + sp_adjust);\n  }\n  return (l);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i,j;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == V_GLOBAL)\n    fprintf(Outfile, \"\\t.export _%s\\n\", node->name);\n  fprintf(Outfile, \"_%s:\\n\", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n    case 1:\n      fprintf(Outfile, \"\\t.byte\\t%d\\n\", initvalue & 0xff);\n      break;\n    case 2:\n      // Generate the pointer to a string literal. Treat a zero value\n      // as actually zero, not the label L0\n      if (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t  && initvalue != 0)\n\tfprintf(Outfile, \"\\t.word\\tL%d\\n\", initvalue);\n      else\n        fprintf(Outfile, \"\\t.word\\t%d\\n\", initvalue & 0xffff);\n      break;\n    case 4:\n\tfprintf(Outfile, \"\\t.word\\t%d\\n\", (initvalue >> 16) & 0xffff);\n\tfprintf(Outfile, \"\\t.word\\t%d\\n\", initvalue & 0xffff);\n      break;\n    default:\n      for (j = 0; j < size; j++)\n\tfprintf(Outfile, \"\\t.byte\\t0\\n\");\n    }\n  }\n}\n\n// Generate a global string and its start label.\nvoid cgglobstr(int l, char *strvalue) {\n  char *cptr;\n  cglabel(l);\n  for (cptr = strvalue; *cptr; cptr++) {\n    fprintf(Outfile, \"\\t.byte\\t%d\\n\", *cptr);\n  }\n  fprintf(Outfile, \"\\t.byte\\t0\\n\");\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] =\n  { \"beq\", \"bne\", \"blt\", \"bgt\", \"ble\", \"bge\" };\n\n// Compare two locations and set if true.\nint cgcompare_and_set(int ASTop, int l1, int l2, int type) {\n  int label1, label2;\n  int primtype = cgprimtype(type);\n\n  // Get two labels\n  label1= genlabel();\n  label2= genlabel();\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  load_d(l1);\n\n  switch (primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\tcmpb \"); printlocation(l2, 0, 'b');\n      break;\n    case PR_INT:\n    case PR_POINTER:\n    case PR_LONG:\n      fprintf(Outfile, \"\\tcmpd \"); printlocation(l2, 0, 'd');\n      break;\n  }\n\n  fprintf(Outfile, \"\\t%s L%d\\n\", cmplist[ASTop - A_EQ], label1);\n\n  // XXX This isn't right and I need to fix it\n  if (primtype==PR_LONG) {\n    fprintf(Outfile, \"\\tbne L%d\\n\", label1);\n    fprintf(Outfile, \"\\tcmpd \"); printlocation(l2, 2, 'd');\n  }\n  fprintf(Outfile, \"\\tldd #0\\n\");\n  fprintf(Outfile, \"\\tbra L%d\\n\", label2);\n  cglabel(label1);\n  fprintf(Outfile, \"\\tldd #1\\n\");\n  cglabel(label2);\n  cgfreelocn(l2);\n\n  // Mark the location as the D register\n  Locn[l1].type= L_DREG;\n  d_holds= l1;\n  return (l1);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  fprintf(Outfile, \"\\tbra L%d\\n\", l);\n  d_holds= NOREG;\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\n\n// Comparisons used by the long function\nstatic char *lcmplist1[] = { \"bne\", \"beq\", \"bge\", \"ble\", \"bgt\", \"blt\" };\nstatic char *lcmplist2[] = { \"bne\", \"beq\", \"bhs\", \"bls\", \"bhi\", \"blo\" };\n\n// Compare two long locations and jump if false\nstatic void longcmp_and_jump(int ASTop, int parentASTop,\n\t\t\t\t\tint l1, int l2, int label) {\n  int truelabel;\n\n  // Generate a new label\n  truelabel=genlabel();\n\n  fprintf(Outfile, \"\\t%s L%d\\n\", lcmplist1[ASTop - A_EQ], label);\n  switch(ASTop) {\n    case A_EQ:\n      fprintf(Outfile, \"\\tbne L%d\\n\", label);\n      break;\n    case A_NE:\n      fprintf(Outfile, \"\\tbne L%d\\n\", truelabel);\n      break;\n    case A_LT:\n      fprintf(Outfile, \"\\tblt L%d\\n\", truelabel);\n      fprintf(Outfile, \"\\tbne L%d\\n\", label);\n      break;\n    case A_GT:\n      fprintf(Outfile, \"\\tbgt L%d\\n\", truelabel);\n      fprintf(Outfile, \"\\tbne L%d\\n\", label);\n      break;\n    case A_LE:\n      fprintf(Outfile, \"\\tbgt L%d\\n\", label);\n      fprintf(Outfile, \"\\tbne L%d\\n\", truelabel);\n      break;\n    case A_GE:\n      fprintf(Outfile, \"\\tblt L%d\\n\", label);\n      fprintf(Outfile, \"\\tbne L%d\\n\", truelabel);\n  }\n\n  fprintf(Outfile, \"\\tcmpd \"); printlocation(l2, 2, 'd');\n  fprintf(Outfile, \"\\t%s L%d\\n\", lcmplist2[ASTop - A_EQ], label);\n  cglabel(truelabel);\n}\n\n// Compare two locations and jump if false.\n// Jump if true if the parent op is A_LOGOR\nint cgcompare_and_jump(int ASTop, int parentASTop,\n\t\t\t\tint l1, int l2, int label, int type) {\n  int primtype = cgprimtype(type);\n  char *jmpop;\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  load_d_z(l1, type);\n  jmpop= invcmplist[ASTop - A_EQ];\n  if (parentASTop==A_LOGOR)\n    jmpop= cmplist[ASTop - A_EQ];\n\n  switch (primtype) {\n    case PR_CHAR:\n      fprintf(Outfile, \"\\tcmpb \"); printlocation(l2, 0, 'b'); break;\n    case PR_INT:\n    case PR_POINTER:\n      fprintf(Outfile, \"\\tcmpd \"); printlocation(l2, 0, 'd'); break;\n    case PR_LONG:\n      fprintf(Outfile, \"\\tcmpy \"); printlocation(l2, 0, 'y'); break;\n  }\n\n  if (primtype==PR_LONG) longcmp_and_jump(ASTop, parentASTop, l1, l2, label);\n  fprintf(Outfile, \"\\t%s L%d\\n\", jmpop, label);\n  cgfreelocn(l1);\n  cgfreelocn(l2);\n  return (NOREG);\n}\n\n// Widen the value in the location from the old\n// to the new type, and return a location\n// with this new value\nint cgwiden(int l, int oldtype, int newtype) {\n  int how= cgprimsize(newtype) - cgprimsize(oldtype);\n  int label1, label2;\n  int l2;\n\n  // If the sizes are the same do nothing\n  if (how==0) return(l);\n\n  load_d(l);\n\n  // Get a location which is a L_DREG\n  l2= cgalloclocn(L_DREG, cgprimtype(newtype), NULL, 0);\n\n  // Three possibilities: size 1 to 2, size 2 to 4 and size 1 to 4.\n  // Note that chars are unsigned which makes things easier\n  switch(how) {\n      // 1 to 2\n    case 1: fprintf(Outfile, \"\\tclra\\n\"); break;\n\n      // 2 to 4\n    case 2:\n      // Get two labels\n      label1 = genlabel();\n      label2 = genlabel();\n      fprintf(Outfile, \"\\tbge L%d\\n\", label1);\n      fprintf(Outfile, \"\\tldy #65535\\n\");\n      fprintf(Outfile, \"\\tbra L%d\\n\", label2);\n      cglabel(label1);\n      fprintf(Outfile, \"\\tldy #0\\n\");\n      cglabel(label2);\n      break;\n\n      // 1 to 4\n    case 3:\n      fprintf(Outfile, \"\\tclra\\n\");\n      fprintf(Outfile, \"\\tldy #0\\n\");\n  }\n\n  return (l2);\n}\n\n// Change a location from its old type to a new type.\nint cgcast(int l, int oldtype, int newtype) {\n  return(cgwiden(l,oldtype,newtype));\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int l, struct symtable *sym) {\n  // Load D is there is a return value\n  if (l != NOREG)\n    load_d(l);\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an identifier.\n// Return a new location\nint cgaddress(struct symtable *sym) {\n  int l;\n\n  // For things not on the stack it's easy\n  if (sym->class == V_GLOBAL ||\n      sym->class == V_EXTERN || sym->class == V_STATIC) {\n    l= cgalloclocn(L_SYMADDR, PR_POINTER, sym->name, 0);\n    return(l);\n  }\n\n  // For things on the stack we need to get the address in\n  // the X register and then move it into D. Stash D in\n  // a temporary if it's already in use.\n  stash_d();\n  fprintf(Outfile, \"\\tleax %d,s\\n\", sym->st_posn + sp_adjust);\n  fprintf(Outfile, \"\\ttfr x,d\\n\");\n  l = cgalloclocn(L_DREG, PR_POINTER, NULL, 0);\n  return(l);\n}\n\n// Dereference a pointer to get the value\n// it points at into the same location\nint cgderef(int l, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  int primtype= cgprimtype(newtype);\n\n  if (Locn[l].type==L_DREG)\n    fprintf(Outfile, \"\\ttfr d,x\\n\");\n  else {\n    // Stash D in a temporary if it's already in use.\n    stash_d();\n    fprintf(Outfile, \"\\tldx \"); printlocation(l, 0, 'd');\n  }\n\n  switch (primtype) {\n  case PR_CHAR:\n    fprintf(Outfile, \"\\tldb 0,x\\n\"); break;\n  case PR_INT:\n  case PR_POINTER:\n    fprintf(Outfile, \"\\tldd 0,x\\n\"); break;\n  case PR_LONG:\n    fprintf(Outfile, \"\\tldd 2,x\\n\");\n    fprintf(Outfile, \"\\tldy 0,x\\n\");\n  }\n\n  cgfreelocn(l);\n  l= cgalloclocn(L_DREG, primtype, NULL, 0);\n  return (l);\n}\n\n// Dereference and store through l2, a pointer\nint cgstorderef(int l1, int l2, int type) {\n  int primtype = cgprimtype(type);\n\n  // If l2 is in the D register, do a transfer\n  if (d_holds== l2) {\n    fprintf(Outfile, \"\\ttfr d,x\\n\");\n  } else {\n    fprintf(Outfile, \"\\tldx \"); printlocation(l2, 0, 'd');\n  }\n\n  d_holds= NOREG;\n  load_d(l1);\n\n  switch (primtype) {\n  case PR_CHAR:\n    fprintf(Outfile, \"\\tstb 0,x\\n\"); break;\n  case PR_INT:\n  case PR_POINTER:\n    fprintf(Outfile, \"\\tstd 0,x\\n\"); break;\n  case PR_LONG:\n    fprintf(Outfile, \"\\tsty 0,x\\n\");\n    fprintf(Outfile, \"\\tstd 2,x\\n\"); break;\n  }\n\n  d_holds= l1;\n  return (11);\n}\n\n// Generate a switch jump table and the code to\n// load the locations and call the switch() code\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n\n  // Get a label for the switch jump table\n  label= genlabel();\n\n  // Generate the switch jump table.\n  cglitseg();\n  cglabel(label);\n  fprintf(Outfile, \"\\t.word %d\\n\", casecount);\n  for (i = 0; i < casecount; i++)\n    fprintf(Outfile, \"\\t.word %d\\n\\t.word L%d\\n\", caseval[i], caselabel[i]);\n  fprintf(Outfile, \"\\t.word L%d\\n\", defaultlabel);\n\n  // Output the label where we restart actual code\n  cgtextseg();\n  cglabel(toplabel);\n\n  // Call the helper routine with the jump table location\n  // after loading D with the value in reg (a location)\n  load_d(reg);\n  fprintf(Outfile, \"\\tldx #L%d\\n\", label);\n  fprintf(Outfile, \"\\tbra __switch\\n\");\n}\n\n// Move value between locations\nvoid cgmove(int l1, int l2, int type) {\n\n  load_d(l1);\n  save_d(l2);\n}\n\n// Output a gdb directive to say on which\n// source code line number the following\n// assembly code came from\nvoid cglinenum(int line) {\n  fprintf(Outfile, \";\\t\\t\\t\\t\\tline %d\\n\", line);\n}\n"
  },
  {
    "path": "64_6809_Target/cgen.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"gen.h\"\n#include \"misc.h\"\n#include \"sym.h\"\n#include \"tree.h\"\n#include \"types.h\"\n\n// Assembly code generator.\n// Copyright (c) 2023,2024 Warren Toomey, GPL3\n\n// Allocate space for the variables\n// then free the symbol table.\nvoid allocateGlobals(void) {\n  struct symtable *sym, *litsym;\n  int i;\n\n  // Load all the types and all the globals\n  loadGlobals();\n\n  // We now have all the types and all the globals in memory\n  // Generate the string literals first\n  for (sym=Symhead; sym!=NULL; sym=sym->next) {\n      if (sym->stype== S_STRLIT)\n \tsym->st_label= genglobstr(sym->name);\n  }\n\n  // Now do the non string literals\n  // XXX To fix: sym=sym->next\n  for (sym=Symhead; sym!=NULL; ) {\n      if (sym->stype== S_STRLIT) { sym=sym->next; continue; }\n\n      // If this is a char pointer or an array of char pointers,\n      // replace any values in the initlist (which are symbol ids)\n      // with the associated string literal labels.\n      // Yes, P_CHAR+2 means array of char pointers.\n      if (sym->initlist!=NULL &&\n        (sym->type== pointer_to(P_CHAR) || sym->type == P_CHAR+2)) {\n        for (i=0; i<sym->nelems; i++)\n          if (sym->initlist[i]!=0) {\n            litsym= findSymbol(NULL, 0, sym->initlist[i]);\n            sym->initlist[i]= litsym->st_label;\n          } \n      }\n      genglobsym(sym);\n      sym=sym->next;\n  }\n  freeSymtable();\t\t// Clear the symbol table\n}\n \n\n// Open the symbol table file and AST file\n// Loop:\n//  Read in the next AST tree\n//  Generate the assembly code\n//  Free the in-memory symbol tables\nint main(int argc, char **argv) {\n  struct ASTnode *node;\n\n  if (argc !=4) {\n    fprintf(stderr, \"Usage: %s symfile astfile idxfile\\n\", argv[0]);\n    exit(1);\n  }\n\n  // Open the symbol table file\n  Symfile= fopen(argv[1], \"r\");\n  if (Symfile == NULL) {\n    fprintf(stderr, \"Can't open %s\\n\", argv[1]); exit(1);\n  }\n\n  // Open the AST file\n  Infile= fopen(argv[2], \"r\");\n  if (Infile == NULL) {\n    fprintf(stderr, \"Can't open %s\\n\", argv[2]); exit(1);\n  }\n\n  // Open the AST index offset file for read/writing\n  Idxfile= fopen(argv[3], \"w+\");\n  if (Idxfile == NULL) {\n    fprintf(stderr, \"Can't open %s\\n\", argv[3]); exit(1);\n  }\n\n  // We write assembly to stdout\n  Outfile=stdout;\n\n  mkASTidxfile();\t\t// Build the AST index offset file\n  freeSymtable();\t\t// Clear the symbol table\n  genpreamble();\t\t// Output the preamble\n  allocateGlobals();\t\t// Allocate global variables\n\n  while (1) {\n    // Read the next function's top node in from file\n    node= loadASTnode(0, 1);\n    if (node==NULL) break;\n\n    // Generate the assembly code for the tree\n    genAST(node, NOLABEL, NOLABEL, NOLABEL, 0);\n\n    // Free the symbols in the in-memory symbol tables.\n    // Also free the AST node we loaded in\n    freeSymtable();\n    freeASTnode(node);\n  }\n\n  genpostamble();               // Output the postamble\n  freeSymtable();\n  fclose(Infile);\n  fclose(Symfile);\n  exit(0);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/cgqbe.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"gen.h\"\n#include \"misc.h\"\n#include \"types.h\"\n#include \"target.h\"\n#include \"cg.h\"\n\n// Code generator for x86-64 using the QBE intermediate language.\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// We have to keep a list of literal strings as we can't generate\n// them in the middle of code\nstruct litlist {\n  char *val;\n  int label;\n  struct litlist *next;\n};\n\nstruct litlist *Strlithead;\nstruct litlist *Strlittail;\n\n// Switch to the text segment\nvoid cgtextseg() {\n}\n\n// Switch to the data segment\nvoid cgdataseg() {\n}\n\n// Switch to the literal segment\nvoid cglitseg() {\n}\n\n// Free registers/temporaries\nvoid cgfreeallregs(int keepreg) {\n}\n\nvoid cgfreereg(int reg) {\n}\n\n// Given a scalar type value, return the\n// character that matches the QBE type.\n// Because chars are stored on the stack,\n// we can return 'w' for P_CHAR.\nstatic int cgprimtype(int type) {\n  if (ptrtype(type))\n    return ('l');\n  switch (type) {\n    case P_VOID:\n      return (' ');\n    case P_CHAR:\n      return ('w');\n    case P_INT:\n      return ('w');\n    case P_LONG:\n      return ('l');\n    default:\n      fatald(\"Bad type in cgprimtype:\", type);\n  }\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Allocate a QBE temporary\nstatic int nexttemp = 0;\nint cgalloctemp(void) {\n  return (++nexttemp);\n}\n\nint cgallocreg(int type) {\n  return(cgalloctemp());\n}\n\n// Print out the assembly preamble\n// for one output file\nvoid cgpreamble() {\n  Strlithead= NULL;\n  Strlittail= NULL;\n}\n\n// Print out any global string literals\nstatic void cgmakeglobstrs();\nvoid cgpostamble() {\n  cgmakeglobstrs();\n}\n\n// Boolean flag: has there been a switch statement\n// in this function yet?\nstatic int used_switch;\n\n// Print out a function preamble\nvoid cgfuncpreamble(struct symtable *sym) {\n  char *name = sym->name;\n  struct symtable *parm, *locvar;\n  int size, bigsize;\n  int label;\n\n  // Output the function's name and return type\n  if (sym->class == V_GLOBAL)\n    fprintf(Outfile, \"export \");\n  fprintf(Outfile, \"function %c $%s(\", cgprimtype(sym->type), name);\n\n  // Output the parameter names and types. For any parameters which\n  // need addresses, change their name as we copy their value below\n  for (parm = sym->member; parm != NULL; parm = parm->next) {\n    if (parm->class==V_LOCAL) break;\n\n    // Ugly. Make all params have a address\n    parm->st_hasaddr = 1;\n    if (parm->st_hasaddr == 1)\n      fprintf(Outfile, \"%c %%.p%s, \", cgprimtype(parm->type), parm->name);\n    else\n      fprintf(Outfile, \"%c %%%s, \", cgprimtype(parm->type), parm->name);\n  }\n  fprintf(Outfile, \") {\\n\");\n\n  // Get a label for the function start\n  label = genlabel();\n  cglabel(label);\n\n  // For any parameters which need addresses, allocate memory\n  // on the stack for them. QBE won't let us do alloc1, so\n  // we allocate 4 bytes for chars. Copy the value from the\n  // parameter to the new memory location.\n  // of the parameter\n  for (parm = sym->member; parm != NULL; parm = parm->next) {\n    if (parm->class==V_LOCAL) break;\n\n    // Ugly. Make all params have a address\n    parm->st_hasaddr = 1;\n    if (parm->st_hasaddr == 1) {\n      size = cgprimsize(parm->type);\n      bigsize = (size == 1) ? 4 : size;\n      fprintf(Outfile, \"  %%%s =l alloc%d 1\\n\", parm->name, bigsize);\n\n      // Copy to the allocated memory\n      switch (size) {\n\tcase 1:\n\t  fprintf(Outfile, \"  storeb %%.p%s, %%%s\\n\", parm->name, parm->name);\n\t  break;\n\tcase 4:\n\t  fprintf(Outfile, \"  storew %%.p%s, %%%s\\n\", parm->name, parm->name);\n\t  break;\n\tcase 8:\n\t  fprintf(Outfile, \"  storel %%.p%s, %%%s\\n\", parm->name, parm->name);\n      }\n    }\n  }\n\n  // Allocate memory for any local variables that need to be on the\n  // stack. There are two reasons for this. The first is for locals\n  // where their address is used. The second is for char variables\n  // We need to do this as QBE can only truncate down to 8 bits\n  // for locations in memory.\n  // Note: locals come after parameters in the member list.\n  for (locvar = parm; locvar != NULL; locvar = locvar->next) {\n    if (locvar->st_hasaddr == 1) {\n      // Get the total size for all elements (if an array).\n      // Round up to the nearest multiple of 8, to ensure that\n      // pointers are aligned on 8-byte boundaries\n      size = locvar->size * locvar->nelems;\n      size = (size + 7) >> 3;\n      fprintf(Outfile, \"  %%%s =l alloc8 %d\\n\", locvar->name, size);\n    } else if (locvar->type == P_CHAR) {\n      locvar->st_hasaddr = 1;\n      fprintf(Outfile, \"  %%%s =l alloc4 1\\n\", locvar->name);\n    }\n  }\n\n  used_switch = 0;\t\t// We haven't output the switch handling code yet\n}\n\n// Print out a function postamble\nvoid cgfuncpostamble(struct symtable *sym) {\n  cglabel(sym->st_endlabel);\n\n  // Return a value if the function's type isn't void\n  if (sym->type != P_VOID)\n    fprintf(Outfile, \"  ret %%.ret\\n}\\n\");\n  else\n    fprintf(Outfile, \"  ret\\n}\\n\");\n}\n\n// Load an integer literal value into a temporary.\n// Return the number of the temporary.\nint cgloadint(int value, int type) {\n  // Get a new temporary\n  int t = cgalloctemp();\n\n  fprintf(Outfile, \"  %%.t%d =%c copy %d\\n\", t, cgprimtype(type), value);\n  return (t);\n}\n\n// Load a value from a variable into a temporary.\n// Return the number of the temporary. If the\n// operation is pre- or post-increment/decrement,\n// also perform this action.\nint cgloadvar(struct symtable *sym, int op) {\n  int r, posttemp, offset = 1;\n  char qbeprefix;\n\n  // Get a new temporary\n  r = cgalloctemp();\n\n  // If the symbol is a pointer, use the size\n  // of the type that it points to as any\n  // increment or decrement. If not, it's one.\n  if (ptrtype(sym->type))\n    offset = typesize(value_at(sym->type), sym->ctype);\n\n  // Negate the offset for decrements\n  if (op == A_PREDEC || op == A_POSTDEC)\n    offset = -offset;\n\n  // Get the relevant QBE prefix for the symbol\n  qbeprefix = ((sym->class == V_GLOBAL) || (sym->class == V_STATIC) ||\n\t       (sym->class == V_EXTERN)) ? (char)'$' : (char)'%';\n\n  // If we have a pre-operation\n  if (op == A_PREINC || op == A_PREDEC) {\n    if (sym->st_hasaddr || qbeprefix == '$') {\n      // Get a new temporary\n      posttemp = cgalloctemp();\n      switch (sym->size) {\n\tcase 1:\n\t  fprintf(Outfile, \"  %%.t%d =w loadub %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  fprintf(Outfile, \"  %%.t%d =w add %%.t%d, %d\\n\", posttemp, posttemp,\n\t\t  offset);\n\t  fprintf(Outfile, \"  storeb %%.t%d, %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  break;\n\tcase 4:\n\t  fprintf(Outfile, \"  %%.t%d =w loadsw %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  fprintf(Outfile, \"  %%.t%d =w add %%.t%d, %d\\n\", posttemp, posttemp,\n\t\t  offset);\n\t  fprintf(Outfile, \"  storew %%.t%d, %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  break;\n\tcase 8:\n\t  fprintf(Outfile, \"  %%.t%d =l loadl %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  fprintf(Outfile, \"  %%.t%d =l add %%.t%d, %d\\n\", posttemp, posttemp,\n\t\t  offset);\n\t  fprintf(Outfile, \"  storel %%.t%d, %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n      }\n    } else\n      fprintf(Outfile, \"  %c%s =%c add %c%s, %d\\n\",\n\t      qbeprefix, sym->name, cgprimtype(sym->type), qbeprefix,\n\t      sym->name, offset);\n  }\n  // Now load the output temporary with the value\n  if (sym->st_hasaddr || qbeprefix == '$') {\n    switch (sym->size) {\n      case 1:\n\tfprintf(Outfile, \"  %%.t%d =w loadub %c%s\\n\", r, qbeprefix,\n\t\tsym->name);\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"  %%.t%d =w loadsw %c%s\\n\", r, qbeprefix,\n\t\tsym->name);\n\tbreak;\n      case 8:\n\tfprintf(Outfile, \"  %%.t%d =l loadl %c%s\\n\", r, qbeprefix, sym->name);\n    }\n  } else\n    fprintf(Outfile, \"  %%.t%d =%c copy %c%s\\n\",\n\t    r, cgprimtype(sym->type), qbeprefix, sym->name);\n\n  // If we have a post-operation\n  if (op == A_POSTINC || op == A_POSTDEC) {\n    if (sym->st_hasaddr || qbeprefix == '$') {\n      // Get a new temporary\n      posttemp = cgalloctemp();\n      switch (sym->size) {\n\tcase 1:\n\t  fprintf(Outfile, \"  %%.t%d =w loadub %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  fprintf(Outfile, \"  %%.t%d =w add %%.t%d, %d\\n\", posttemp, posttemp,\n\t\t  offset);\n\t  fprintf(Outfile, \"  storeb %%.t%d, %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  break;\n\tcase 4:\n\t  fprintf(Outfile, \"  %%.t%d =w loadsw %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  fprintf(Outfile, \"  %%.t%d =w add %%.t%d, %d\\n\", posttemp, posttemp,\n\t\t  offset);\n\t  fprintf(Outfile, \"  storew %%.t%d, %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  break;\n\tcase 8:\n\t  fprintf(Outfile, \"  %%.t%d =l loadl %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n\t  fprintf(Outfile, \"  %%.t%d =l add %%.t%d, %d\\n\", posttemp, posttemp,\n\t\t  offset);\n\t  fprintf(Outfile, \"  storel %%.t%d, %c%s\\n\", posttemp, qbeprefix,\n\t\t  sym->name);\n      }\n    } else\n      fprintf(Outfile, \"  %c%s =%c add %c%s, %d\\n\",\n\t      qbeprefix, sym->name, cgprimtype(sym->type), qbeprefix,\n\t      sym->name, offset);\n  }\n  // Return the temporary with the value\n  return (r);\n}\n\n// Given the label number of a global string,\n// load its address into a new temporary\nint cgloadglobstr(int label) {\n  // Get a new temporary\n  int r = cgalloctemp();\n  fprintf(Outfile, \"  %%.t%d =l copy $L%d\\n\", r, label);\n  return (r);\n}\n\n// Add two temporaries together and return\n// the number of the temporary with the result\nint cgadd(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c add %%.t%d, %%.t%d\\n\",\n\t  r1, cgprimtype(type), r1, r2);\n  return (r1);\n}\n\n// Subtract the second temporary from the first and\n// return the number of the temporary with the result\nint cgsub(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c sub %%.t%d, %%.t%d\\n\",\n\t  r1, cgprimtype(type), r1, r2);\n  return (r1);\n}\n\n// Multiply two temporaries together and return\n// the number of the temporary with the result\nint cgmul(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c mul %%.t%d, %%.t%d\\n\",\n\t  r1, cgprimtype(type), r1, r2);\n  return (r1);\n}\n\n// Divide the first temporary by the second and\n// return the number of the temporary with the result\nint cgdiv(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c div %%.t%d, %%.t%d\\n\",\n\t    r1, cgprimtype(type), r1, r2);\n  return (r1);\n}\n\n// Modulo the first temporary by the second and\n// return the number of the temporary with the result\nint cgmod(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c rem %%.t%d, %%.t%d\\n\",\n\t    r1, cgprimtype(type), r1, r2);\n  return (r1);\n}\n\n// Bitwise AND two temporaries\nint cgand(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c and %%.t%d, %%.t%d\\n\",\n\t  r1, cgprimtype(type), r1, r2);\n  return (r1);\n}\n\n// Bitwise OR two temporaries\nint cgor(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c or %%.t%d, %%.t%d\\n\",\n\t  r1, cgprimtype(type), r1, r2);\n  return (r1);\n}\n\n// Bitwise XOR two temporaries\nint cgxor(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c xor %%.t%d, %%.t%d\\n\",\n\t  r1, cgprimtype(type), r1, r2);\n  return (r1);\n}\n\n// Shift left r1 by r2 bits\nint cgshl(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c shl %%.t%d, %%.t%d\\n\",\n\t  r1, cgprimtype(type), r1, r2);\n  return (r1);\n}\n\n// Shift right r1 by r2 bits\nint cgshr(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c shr %%.t%d, %%.t%d\\n\",\n\t  r1, cgprimtype(type), r1, r2);\n  return (r1);\n}\n\n// Negate a temporary's value\nint cgnegate(int r, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c sub 0, %%.t%d\\n\", r, cgprimtype(type), r);\n  return (r);\n}\n\n// Invert a temporary's value\nint cginvert(int r, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c xor %%.t%d, -1\\n\", r, cgprimtype(type), r);\n  return (r);\n}\n\n// Logically negate a temporary's value\nint cglognot(int r, int type) {\n  int q = cgprimtype(type);\n  fprintf(Outfile, \"  %%.t%d =%c ceq%c %%.t%d, 0\\n\", r, q, q, r);\n  return (r);\n}\n\n// Load a boolean value (only 0 or 1)\n// into the given temporary. Allocate a\n// temporary if r is NOREG\nint cgloadboolean(int r, int val, int type) {\n  if (r==NOREG) r= cgalloctemp();\n  fprintf(Outfile, \"  %%.t%d =%c copy %d\\n\", r, cgprimtype(type), val);\n  return(r);\n}\n\n// Convert an integer value to a boolean value for\n// a TOBOOL operation. Jump if true if it's an IF, \n// WHILE operation. Jump if false if it's \n// a LOGOR operation.\nint cgboolean(int r, int op, int label, int type) {\n  // Get a label for the next instruction\n  int label2 = genlabel();\n\n  // Get a new temporary for the comparison\n  int r2 = cgalloctemp();\n\n  // Convert temporary to boolean value\n  fprintf(Outfile, \"  %%.t%d =l cne%c %%.t%d, 0\\n\", r2, cgprimtype(type), r);\n\n  switch (op) {\n    case A_IF:\n    case A_WHILE:\n    case A_TERNARY:\n    case A_LOGAND:\n      fprintf(Outfile, \"  jnz %%.t%d, @L%d, @L%d\\n\", r2, label2, label);\n      break;\n    case A_LOGOR:\n      fprintf(Outfile, \"  jnz %%.t%d, @L%d, @L%d\\n\", r2, label, label2);\n      break;\n  }\n\n  // Output the label for the next instruction\n  cglabel(label2);\n  return (r2);\n}\n\n// Call a function with the given symbol id.\n// Return the temprary with the result\nint cgcall(struct symtable *sym, int numargs, int *arglist, int *typelist) {\n  int outr;\n  int i;\n\n  // Get a new temporary for the return result\n  outr = cgalloctemp();\n\n  // Call the function\n  if (sym->type == P_VOID)\n    fprintf(Outfile, \"  call $%s(\", sym->name);\n  else\n    fprintf(Outfile, \"  %%.t%d =%c call $%s(\", outr, cgprimtype(sym->type),\n\t    sym->name);\n\n  // Output the list of arguments\n  for (i = numargs - 1; i >= 0; i--) {\n    fprintf(Outfile, \"%c %%.t%d, \", cgprimtype(typelist[i]), arglist[i]);\n  }\n  fprintf(Outfile, \")\\n\");\n\n  return (outr);\n}\n\n// Shift a temporary left by a constant. As we only\n// use this for address calculations, extend the\n// type to be a QBE 'l' if required\nint cgshlconst(int r, int val, int type) {\n  int r2 = cgalloctemp();\n  int r3 = cgalloctemp();\n\n  if (cgprimsize(type) < 8) {\n    fprintf(Outfile, \"  %%.t%d =l extsw %%.t%d\\n\", r2, r);\n    fprintf(Outfile, \"  %%.t%d =l shl %%.t%d, %d\\n\", r3, r2, val);\n  } else\n    fprintf(Outfile, \"  %%.t%d =l shl %%.t%d, %d\\n\", r3, r, val);\n  return (r3);\n}\n\n// Store a temporary's value into a global variable\nint cgstorglob(int r, struct symtable *sym) {\n\n  // We can store to bytes in memory\n  int q = cgprimtype(sym->type);\n  if (sym->type == P_CHAR)\n    q = 'b';\n\n  fprintf(Outfile, \"  store%c %%.t%d, $%s\\n\", q, r, sym->name);\n  return (r);\n}\n\n// Store a temporary's value into a local variable\nint cgstorlocal(int r, struct symtable *sym) {\n\n  // If the variable is on the stack, use store instructions\n  if (sym->st_hasaddr) {\n    fprintf(Outfile, \"  store%c %%.t%d, %%%s\\n\",\n\t    cgprimtype(sym->type), r, sym->name);\n  } else {\n    fprintf(Outfile, \"  %%%s =%c copy %%.t%d\\n\",\n\t    sym->name, cgprimtype(sym->type), r);\n  }\n  return (r);\n}\n\n// Generate a global symbol but not functions\nvoid cgglobsym(struct symtable *node) {\n  int size, type;\n  int initvalue;\n  int i;\n\n  if (node == NULL)\n    return;\n  if (node->stype == S_FUNCTION)\n    return;\n\n  // Get the size of the variable (or its elements if an array)\n  // and the type of the variable\n  if (node->stype == S_ARRAY) {\n    size = typesize(value_at(node->type), node->ctype);\n    type = value_at(node->type);\n  } else {\n    size = node->size;\n    type = node->type;\n  }\n\n  // Generate the global identity and the label\n  cgdataseg();\n  if (node->class == V_GLOBAL)\n    fprintf(Outfile, \"export \");\n  if (node->ctype==NULL)\n    fprintf(Outfile, \"data $%s = align %d { \", node->name, cgprimsize(type));\n  else\n    fprintf(Outfile, \"data $%s = align 8 { \", node->name);\n\n  // Output space for one or more elements\n  for (i = 0; i < node->nelems; i++) {\n\n    // Get any initial value\n    initvalue = 0;\n    if (node->initlist != NULL)\n      initvalue = node->initlist[i];\n\n    // Generate the space for this type\n    switch (size) {\n      case 1:\n\tfprintf(Outfile, \"b %d, \", initvalue);\n\tbreak;\n      case 4:\n\tfprintf(Outfile, \"w %d, \", initvalue);\n\tbreak;\n      case 8:\n\t// Generate the pointer to a string literal. Treat a zero value\n\t// as actually zero, not the label L0\n\tif (node->initlist != NULL && type == pointer_to(P_CHAR)\n\t    && initvalue != 0)\n\t  fprintf(Outfile, \"l $L%d, \", initvalue);\n\telse\n\t  fprintf(Outfile, \"l %d, \", initvalue);\n\tbreak;\n      default:\n\tfprintf(Outfile, \"z %d, \", size);\n    }\n  }\n  fprintf(Outfile, \"}\\n\");\n}\n\n// Stash a global string for later output\nvoid cgglobstr(int l, char *strvalue) {\n  struct litlist *this;\n\n  this= (struct litlist *)malloc(sizeof(struct litlist));\n  this->val= strdup(strvalue);\n  this->label= l;\n  this->next= NULL;\n  if (Strlithead==NULL) {\n    Strlithead= Strlittail= this;\n  } else {\n    Strlittail->next= this; Strlittail= this;\n  }\n}\n\n// Generate all the global strings and their labels\nstatic void cgmakeglobstrs() {\n  struct litlist *this;\n  char *cptr;\n\n  for (this= Strlithead; this!=NULL; this=this->next) {\n\n    fprintf(Outfile, \"data $L%d = { \", this->label);\n    for (cptr = this->val; *cptr; cptr++) {\n      fprintf(Outfile, \"b %d, \", *cptr);\n    }\n    fprintf(Outfile, \" b 0 }\\n\");\n  }\n}\n\n// NUL terminate a global string\nvoid cgglobstrend(void) {\n}\n\n// List of comparison instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *cmplist[] = { \"ceq\", \"cne\", \"cslt\", \"csgt\", \"csle\", \"csge\" };\n\n// Compare two temporaries and set if true.\nint cgcompare_and_set(int ASTop, int r1, int r2, int type) {\n  int r3;\n  int q = cgprimtype(type);\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  // Get a new temporary for the comparison\n  r3 = cgalloctemp();\n\n  fprintf(Outfile, \"  %%.t%d =%c %s%c %%.t%d, %%.t%d\\n\",\n\t  r3, q, cmplist[ASTop - A_EQ], q, r1, r2);\n  return (r3);\n}\n\n// Generate a label\nvoid cglabel(int l) {\n  fprintf(Outfile, \"@L%d\\n\", l);\n}\n\n// Generate a jump to a label\nvoid cgjump(int l) {\n  int label;\n\n  fprintf(Outfile, \"  jmp @L%d\\n\", l);\n\n  // Print out a bogus label. This prevents the output\n  // having two adjacent jumps which QBE doesn't like.\n  label = genlabel();\n  cglabel(label);\n}\n\n// List of inverted jump instructions,\n// in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE\nstatic char *invcmplist[] = { \"cne\", \"ceq\", \"csge\", \"csle\", \"csgt\", \"cslt\" };\n\n// Compare two temporaries and jump if false.\n// Jump if true if the parent op is A_LOGOR.\nint cgcompare_and_jump(int ASTop, int parentASTop,\n\t\t\t\tint r1, int r2, int label, int type) {\n  int label2;\n  int r3;\n  int q = cgprimtype(type);\n  char *cmpop;\n\n  // Check the range of the AST operation\n  if (ASTop < A_EQ || ASTop > A_GE)\n    fatal(\"Bad ASTop in cgcompare_and_set()\");\n\n  cmpop= invcmplist[ASTop - A_EQ];\n  if (parentASTop == A_LOGOR)\n    cmpop= cmplist[ASTop - A_EQ];\n\n  // Get a label for the next instruction\n  label2 = genlabel();\n\n  // Get a new temporary for the comparison\n  r3 = cgalloctemp();\n\n  fprintf(Outfile, \"  %%.t%d =%c %s%c %%.t%d, %%.t%d\\n\",\n\t  r3, q, cmpop, q, r1, r2);\n  fprintf(Outfile, \"  jnz %%.t%d, @L%d, @L%d\\n\", r3, label, label2);\n  cglabel(label2);\n  return (NOREG);\n}\n\n// Widen the value in the temporary from the old\n// to the new type, and return a temporary with\n// this new value\nint cgwiden(int r, int oldtype, int newtype) {\n  int oldq = cgprimtype(oldtype);\n  int newq = cgprimtype(newtype);\n\n  // Get a new temporary\n  int t = cgalloctemp();\n\n  switch (oldtype) {\n    case P_CHAR:\n      fprintf(Outfile, \"  %%.t%d =%c extub %%.t%d\\n\", t, newq, r);\n      break;\n    default:\n      fprintf(Outfile, \"  %%.t%d =%c exts%c %%.t%d\\n\", t, newq, oldq, r);\n  }\n  return (t);\n}\n\n// Generate code to return a value from a function\nvoid cgreturn(int r, struct symtable *sym) {\n  // Only return a value if we have a value to return\n  if (r != NOREG)\n    fprintf(Outfile, \"  %%.ret =%c copy %%.t%d\\n\", cgprimtype(sym->type), r);\n\n  cgjump(sym->st_endlabel);\n}\n\n// Generate code to load the address of an\n// identifier. Return a new temporary\nint cgaddress(struct symtable *sym) {\n  int r = cgalloctemp();\n  char qbeprefix = ((sym->class == V_GLOBAL) || (sym->class == V_STATIC) ||\n\t\t    (sym->class == V_EXTERN)) ? (char)'$' : (char)'%';\n\n  fprintf(Outfile, \"  %%.t%d =l copy %c%s\\n\", r, qbeprefix, sym->name);\n  return (r);\n}\n\n// Dereference a pointer to get the value\n// it points at into a new temporary\nint cgderef(int r, int type) {\n  // Get the type that we are pointing to\n  int newtype = value_at(type);\n  // Now get the size of this type\n  int size = cgprimsize(newtype);\n  // Get temporary for the return result\n  int ret = cgalloctemp();\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"  %%.t%d =w loadub %%.t%d\\n\", ret, r);\n      break;\n    case 4:\n      fprintf(Outfile, \"  %%.t%d =w loadsw %%.t%d\\n\", ret, r);\n      break;\n    case 8:\n      fprintf(Outfile, \"  %%.t%d =l loadl %%.t%d\\n\", ret, r);\n      break;\n    default:\n      fatald(\"Can't cgderef on type:\", type);\n  }\n  return (ret);\n}\n\n// Store through a dereferenced pointer\nint cgstorderef(int r1, int r2, int type) {\n  // Get the size of the type\n  int size = cgprimsize(type);\n\n  switch (size) {\n    case 1:\n      fprintf(Outfile, \"  storeb %%.t%d, %%.t%d\\n\", r1, r2);\n      break;\n    case 4:\n      fprintf(Outfile, \"  storew %%.t%d, %%.t%d\\n\", r1, r2);\n      break;\n    case 8:\n      fprintf(Outfile, \"  storel %%.t%d, %%.t%d\\n\", r1, r2);\n      break;\n    default:\n      fatald(\"Can't cgstoderef on type:\", type);\n  }\n  return (r1);\n}\n\n// Generate code to compare each switch value\n// and jump to the appropriate case label.\nvoid cgswitch(int reg, int casecount, int toplabel,\n\t      int *caselabel, int *caseval, int defaultlabel) {\n  int i, label;\n  int rval, rcmp;\n\n  // Get two temporaries for the case value and the comparison\n  rval= cgalloctemp();\n  rcmp= cgalloctemp();\n\n  // Output the label at the top of the code\n  cglabel(toplabel);\n\n  for (i = 0; i < casecount; i++) {\n    // Get a label for the code when we skip this case\n    label= genlabel();\n\n    // Load the case value \n    fprintf(Outfile, \"  %%.t%d =w copy %d\\n\", rval, caseval[i]);\n\n    // Compare the temporary against the case value\n    fprintf(Outfile, \"  %%.t%d =w ceqw %%.t%d, %%.t%d\\n\", rcmp, reg, rval);\n\n    // Jump either to the next comparison or the case code\n    fprintf(Outfile, \"  jnz %%.t%d, @L%d, @L%d\\n\", rcmp, caselabel[i], label);\n    cglabel(label);\n  }\n\n  // No case matched, jump to the default label\n  cgjump(defaultlabel);\n}\n\n// Move value between temporaries\nvoid cgmove(int r1, int r2, int type) {\n  fprintf(Outfile, \"  %%.t%d =%c copy %%.t%d\\n\", r2, cgprimtype(type), r1);\n}\n\n// Output a gdb directive to say on which\n// source code line number the following\n// assembly code came from\nvoid cglinenum(int line) {\n  // fprintf(Outfile, \"\\t.loc 1 %d 0\\n\", line);\n}\n\n// Change a temporary value from its old\n// type to a new type.\nint cgcast(int t, int oldtype, int newtype) {\n  // Get temporary for the return result\n  int ret = cgalloctemp();\n  int oldsize, newsize;\n  int qnew;\n\n  // If the new type is a pointer\n  if (ptrtype(newtype)) {\n    // Nothing to do if the old type is also a pointer\n    if (ptrtype(oldtype))\n      return (t);\n    // Otherwise, widen from a primitive type to a pointer\n    return (cgwiden(t, oldtype, newtype));\n  }\n\n  // New type is not a pointer\n  // Get the new QBE type\n  // and the type sizes in bytes\n  qnew = cgprimtype(newtype);\n  oldsize = cgprimsize(oldtype);\n  newsize = cgprimsize(newtype);\n\n  // Nothing to do if the two are the same size\n  if (newsize == oldsize)\n    return (t);\n\n  // If the new size is smaller, we can copy and QBE will truncate it,\n  // otherwise use the QBE cast operation\n  if (newsize < oldsize)\n    fprintf(Outfile, \" %%.t%d =%c copy %%.t%d\\n\", ret, qnew, t);\n  else\n    fprintf(Outfile, \" %%.t%d =%c cast %%.t%d\\n\", ret, qnew, t);\n  return (ret);\n}\n"
  },
  {
    "path": "64_6809_Target/cpeep.c",
    "content": "/* copt version 1.00 (C) Copyright Christopher W. Fraser 1984 */\n/* Added out of memory checking and ANSI prototyping. DG 1999 */\n/* Added %L - %N variables, %activate, regexp, %check. Zrin Z. 2002 */\n\n#include <ctype.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n\nint rpn_eval(char *expr, char **vars);\n\n#define HSIZE 107\n#define MAXLINE 128\n#define MAXFIRECOUNT 65535L\n#define MAX_PASS 16\n\nint debug = 0;\n\nint global_again = 0;\t\t\t/* signalize rule set has changed */\n#define FIRSTLAB 'L'\n#define LASTLAB 'N'\nint nextlab = 1;\t\t\t/* unique label counter */\nint labnum[LASTLAB - FIRSTLAB + 1];\t/* unique label numbers */\n\nstruct lnode {\n  char *l_text;\n  struct lnode *l_prev, *l_next;\n};\n\nstruct onode {\n  struct lnode *o_old, *o_new;\n  struct onode *o_next;\n  long firecount;\n} *opts, *activerule;\n\nvoid printlines(struct lnode *beg, struct lnode *end, FILE * out) {\n  struct lnode *p;\n  for (p = beg; p != end; p = p->l_next)\n    fputs(p->l_text, out);\n}\n\nvoid printrule(struct onode *o, FILE * out) {\n  struct lnode *p = o->o_old;\n  while (p->l_prev)\n    p = p->l_prev;\n  printlines(p, NULL, out);\n  fputs(\"=\\n\", out);\n  printlines(o->o_new, NULL, out);\n}\n\n/* error - report error and quit */\nvoid error(char *s) {\n  fputs(s, stderr);\n  if (activerule) {\n    fputs(\"active rule:\\n\", stderr);\n    printrule(activerule, stderr);\n  }\n  exit(1);\n}\n\n/* connect - connect p1 to p2 */\nvoid connect(struct lnode *p1, struct lnode *p2) {\n  if (p1 == NULL || p2 == NULL)\n    error(\"connect: can't happen\\n\");\n  p1->l_next = p2;\n  p2->l_prev = p1;\n}\n\n static struct hnode {\n    char *h_str;\n    struct hnode *h_ptr;\n} *htab[HSIZE];\n\n/* install - install str in string table */\nchar *install(char *str) {\n  char *p1, *p2, *s;\n  int i;\n  struct hnode *p;\n\n\n  s = str;\n  for (i = 0; *s; i += *s++);\n  i = abs(i) % HSIZE;\n\n  for (p = htab[i]; p; p = p->h_ptr)\n    for (p1 = str, p2 = p->h_str; *p1++ == *p2++;)\n      if (p1[-1] == '\\0')\n\treturn (p->h_str);\n\n  p = (struct hnode *) malloc(sizeof(struct hnode));\n  if (p == NULL)\n    error(\"install 1: out of memory\\n\");\n\n  p->h_str = (char *) malloc((s - str) + 1);\n  if (p->h_str == NULL)\n    error(\"install 2: out of memory\\n\");\n\n  strcpy(p->h_str, str);\n  p->h_ptr = htab[i];\n  htab[i] = p;\n  return (p->h_str);\n}\n\n/* insert - insert a new node with text s before node p */\nvoid insert(char *s, struct lnode *p) {\n  struct lnode *n;\n\n  n = (struct lnode *) malloc(sizeof(struct lnode));\n  if (n == NULL)\n    error(\"insert: out of memory\\n\");\n\n  n->l_text = s;\n  connect(p->l_prev, n);\n  connect(n, p);\n}\n\n/* getlst - link lines from fp in between p1 and p2 */\nvoid getlst(FILE * fp, char *quit, struct lnode *p1, struct lnode *p2) {\n  char lin[MAXLINE];\n\n  connect(p1, p2);\n  while (fgets(lin, MAXLINE, fp) != NULL && strcmp(lin, quit)) {\n    insert(install(lin), p2);\n  }\n}\n\n/* getlst_1 - link lines from fp in between p1 and p2 */\n/* skip blank lines and comments at the start */\nvoid getlst_1(FILE * fp, char *quit, struct lnode *p1, struct lnode *p2) {\n  char lin[MAXLINE];\n  int firstline = 1;\n\n  connect(p1, p2);\n  while (fgets(lin, MAXLINE, fp) != NULL && strcmp(lin, quit)) {\n    if (firstline) {\n      char *p = lin;\n      if (lin[0] == '#') continue;\n      while (isspace(*p)) ++p;\n      if (!*p) continue;\n      firstline = 0;\n    }\n\n    insert(install(lin), p2);\n  }\n}\n\n/* init - read patterns file */\nvoid init(FILE * fp) {\n  struct lnode head, tail;\n  struct onode *p, **next;\n\n  next = &opts;\n  while (*next)\n    next = &((*next)->o_next);\n  while (!feof(fp)) {\n    p = (struct onode *) malloc((unsigned) sizeof(struct onode));\n    if (p == NULL)\n      error(\"init: out of memory\\n\");\n    p->firecount = MAXFIRECOUNT;\n    getlst_1(fp, \"=\\n\", &head, &tail);\n    head.l_next->l_prev = NULL;\n    if (tail.l_prev)\n      tail.l_prev->l_next = NULL;\n    p->o_old = tail.l_prev;\n    if (p->o_old == NULL) {\t/* do not create empty rules */\n      free(p);\n      continue;\n    }\n    getlst(fp, \"====\\n\", &head, &tail);\n    tail.l_prev->l_next = NULL;\n    if (head.l_next)\n      head.l_next->l_prev = NULL;\n    p->o_new = head.l_next;\n\n    *next = p;\n    next = &p->o_next;\n  }\n\n  *next = NULL;\n}\n\n/* match - check conditions in rules */\n/* format: %check min <= %n <= max */\nint check(char *pat, char **vars) {\n  int low, high, x;\n  char v;\n  x = sscanf(pat, \"%d <= %%%c <= %d\", &low, &v, &high);\n  if (x != 3 || !('0' <= v && v <= '9')) {\n    fprintf(stderr, \"warning: invalid use of '%%check' in \\\"%s\\\"\\n\", pat);\n    fprintf(stderr, \"format is '%%check min <= %%n <= max'\\n\");\n    return 0;\n  }\n\n  if (vars[v - '0'] == 0) {\n    fprintf(stderr, \"error in pattern \\\"%s\\\"\\n\", pat);\n    error(\"variable is not set\\n\");\n  }\n\n  if (sscanf(vars[v - '0'], \"%d\", &x) != 1)\n    return 0;\n  return low <= x && x <= high;\n}\n\nint check_eval(char *pat, char **vars) {\n  char expr[1024];\n  int expected, x;\n\n  x = sscanf(pat, \"%d = %[^\\n]s\", &expected, expr);\n  if (x != 2) {\n    fprintf(stderr, \"warning: invalid use of '%%check_eval' in \\\"%s\\\"\\n\",\n\t    pat);\n    fprintf(stderr, \"format is '%%check_eval result = expr\");\n    return 0;\n  }\n\n  return expected == rpn_eval(expr, vars);\n}\n\n/* match - match ins against pat and set vars */\nint match(char *ins, char *pat, char **vars) {\n  char *p, lin[MAXLINE], *start = pat;\n\n  while (*ins && *pat)\n    if (pat[0] == '%') {\n      switch (pat[1]) {\n      case '%':\n\tif (*pat != *ins++)\n\t  return 0;\n\tpat += 2;\n\tbreak;\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n      case '8':\n      case '9':\n\tif (pat[2] == '%' && pat[3] != '%') {\n\t  fprintf(stderr, \"error in \\\"%s\\\": \", start);\n\t  error(\"input pattern %n% is not allowed\\n\");\n\t}\n\n\tfor (p = lin; *ins && *ins != pat[2];)\n\t  *p++ = *ins++;\n\t*p = 0;\n\tp = install(lin);\n\tif (vars[pat[1] - '0'] == 0)\n\t  vars[pat[1] - '0'] = p;\n\telse if (vars[pat[1] - '0'] != p)\n\t  return 0;\n\tpat += 2;\n\tcontinue;\n\n      default:\n\tbreak;\n      }\n\n      if (*pat++ != *ins++)\n\treturn 0;\n    } else if (*pat++ != *ins++)\n      return 0;\n\n  return *pat == *ins;\t\t/* compare end of string */\n}\n\n/* subst_imp - return result of substituting vars into pat */\nchar *subst_imp(char *pat, char **vars) {\n  static char errormsg[80];\n  static char lin[MAXLINE];\n  char num[30];\n  char *s, *start = pat;\n  int i;\n\n  i = 0;\n  for (;;) {\n    if (pat[0] == '%' && pat[1] == '%') {\n      if (i < MAXLINE) {\n\tlin[i] = '%';\n\t++i;\n      }\n\n      pat += 2;\n    } else if (pat[0] == '%' && pat[1] >= FIRSTLAB && pat[1] <= LASTLAB) {\n      int il = pat[1] - FIRSTLAB;\n      if (!labnum[il])\n\tlabnum[il] = nextlab++;\n      sprintf(num, \"%d\", labnum[il]);\n      for (s = num; i < MAXLINE && (lin[i] = *s++) != 0; ++i);\n      pat += 2;\n    } else if (pat[0] == '%' && strncmp(pat, \"%eval(\", 6) == 0) {\n      char expr[1024];\n      int x = 0, r;\n      pat += 6;\n      while (*pat != ')') {\n\texpr[x++] = *pat++;\n      }\n\n      expr[x] = 0;\n      pat++;\n      r = rpn_eval(expr, vars);\n      sprintf(expr, \"%d\", r);\n      for (s = expr; i < MAXLINE && *s; i++)\n\tlin[i] = *s++;\n    } else if (pat[0] == '%' && isdigit(pat[1])) {\n      if (vars[pat[1] - '0'] == 0) {\n\tsprintf(errormsg, \"error: variable %c is not set in \\\"%s\\\"\",\n\t\tpat[1], start);\n\terror(errormsg);\n      }\n      for (s = vars[pat[1] - '0']; i < MAXLINE && (lin[i] = *s++) != 0; i++);\n      pat += 2;\n    } else if (i >= MAXLINE)\n      error(\"line too long\\n\");\n    else if (!(lin[i++] = *pat++))\n      return &lin[0];\n  }\n}\n\n/* subst - return install(result of substituting vars into pat) */\nchar *subst(char *pat, char **vars) {\n  return install(subst_imp(pat, vars));\n}\n\n/* rep - substitute vars into new and replace lines between p1 and p2 */\nstruct lnode *rep(struct lnode *p1, struct lnode *p2, struct lnode *new,\n\t\t  char **vars) {\n  int i;\n  struct lnode *p, *psav;\n\n  for (i = 0; i < LASTLAB - FIRSTLAB + 1; ++i)\n    labnum[i] = 0;\n\n  for (p = p1->l_next; p != p2; p = psav) {\n    psav = p->l_next;\n    if (debug)\n      fputs(p->l_text, stderr);\n    free(p);\n  }\n  connect(p1, p2);\n  if (debug)\n    fputs(\"=\\n\", stderr);\n  for (; new; new = new->l_next) {\n    insert(subst(new->l_text, vars), p2);\n    if (debug)\n      fputs(p2->l_prev->l_text, stderr);\n  }\n  if (debug)\n    putc('\\n', stderr);\n  return p1->l_next;\n}\n\n/* copylist - copy activated rule; substitute variables */\nstruct lnode *copylist(struct lnode *source, struct lnode **pat,\n\t\t       struct lnode **sub, char **vars) {\n  struct lnode head, tail, *more = NULL;\n  int pattern = 1;\t\t/* allow nested rules */\n  int i;\n  connect(&head, &tail);\n  head.l_prev = tail.l_next = NULL;\n\n  for (i = 0; i < LASTLAB - FIRSTLAB + 1; ++i)\n    labnum[i] = 0;\n\n  for (; source; source = source->l_next) {\n    if (pattern && strcmp(source->l_text, \"=\\n\") == 0) {\n      pattern = 0;\n      if (head.l_next == &tail)\n\terror(\"error: empty pattern\\n\");\n      *pat = tail.l_prev;\n      head.l_next->l_prev = NULL;\n      tail.l_prev->l_next = NULL;\n      connect(&head, &tail);\n      continue;\n    }\n    if (strcmp(source->l_text, \"%activate\\n\") == 0) {\n      if (pattern)\n\terror(\"error: %activate in pattern (before '=')\\n\");\n      more = source->l_next;\n      break;\n    }\n    insert(subst(source->l_text, vars), &tail);\n  }\n  if (head.l_next == &tail)\n    *sub = NULL;\n  else {\n    head.l_next->l_prev = NULL;\n    tail.l_prev->l_next = NULL;\n    *sub = head.l_next;\n  }\n  return more;\n}\n\n/* opt - replace instructions ending at r if possible */\nstruct lnode *opt(struct lnode *r) {\n  char *vars[10];\n  int i, lines;\n  struct lnode *c, *p;\n  struct onode *o;\n  static char *activated = \"%activated \";\n\n  for (o = opts; o; o = o->o_next) {\n    activerule = o;\n    if (o->firecount < 1)\n      continue;\n    c = r;\n    p = o->o_old;\n    if (debug) {\n      fprintf(stderr, \"Trying rule: \");\n      printrule(o, stderr);\n    }\n    if (p == NULL)\n      continue;\t\t\t/* skip empty rules */\n    for (i = 0; i < 10; i++)\n      vars[i] = 0;\n    lines = 0;\n    while (p && c) {\n      if (strncmp(p->l_text, \"%check\", 6) == 0) {\n\tif (!check(p->l_text + 6, vars))\n\t  break;\n      } else if (strncmp(p->l_text, \"%eval\", 5) == 0) {\n\tif (!check_eval(p->l_text + 5, vars))\n\t  break;\n      } else {\n//                fprintf(stderr, \"Matching '%s', '%s'.\\n\",\n//                    c->l_text, p->l_text);\n\tif (!match(c->l_text, p->l_text, vars))\n\t  break;\n\tc = c->l_prev;\n\t++lines;\n      }\n      p = p->l_prev;\n    }\n    if (p != NULL)\n      continue;\n\n    /* decrease firecount */\n    --o->firecount;\n\n    /* check for %once */\n    if (o->o_new && strcmp(o->o_new->l_text, \"%once\\n\") == 0) {\n      struct lnode *tmp = o->o_new;\t/* delete the %once line */\n      o->o_new = o->o_new->l_next;\n      o->o_new->l_prev = NULL;\n      free(tmp);\n      o->firecount = 0;\t\t/* never again */\n    }\n\n    /* check for activation rules */\n    if (o->o_new && strcmp(o->o_new->l_text, \"%activate\\n\") == 0) {\n      /* we have to prevent repeated activation of rules */\n      char signature[300];\n      struct lnode *lnp;\n      struct onode *nn, *last;\n      int skip = 0;\n      /* since we 'install()' strings, we can compare pointers */\n      sprintf(signature, \"%s%p%p%p%p%p%p%p%p%p%p\\n\",\n\t      activated,\n\t      vars[0], vars[1], vars[2], vars[3], vars[4],\n\t      vars[5], vars[6], vars[7], vars[8], vars[9]);\n      lnp = o->o_new->l_next;\n      while (lnp && strncmp(lnp->l_text, activated, strlen(activated)) == 0) {\n\tif (strcmp(lnp->l_text, signature) == 0) {\n\t  skip = 1;\n\t  break;\n\t}\n\tlnp = lnp->l_next;\n      }\n      if (!lnp || skip)\n\tcontinue;\n      insert(install(signature), lnp);\n\n      if (debug) {\n\tfputs(\"matched pattern:\\n\", stderr);\n\tfor (p = o->o_old; p->l_prev; p = p->l_prev);\n\tprintlines(p, NULL, stderr);\n\tfputs(\"with:\\n\", stderr);\n\tprintlines(c->l_next, r->l_next, stderr);\n      }\n      /* allow creation of several rules */\n      last = o;\n      while (lnp) {\n\tnn = (struct onode *)\n\t  malloc((unsigned) sizeof(struct onode));\n\tif (nn == NULL)\n\t  error(\"activate: out of memory\\n\");\n\tnn->o_old = 0, nn->o_new = 0;\n\tnn->firecount = MAXFIRECOUNT;\n\tlnp = copylist(lnp, &nn->o_old, &nn->o_new, vars);\n\tnn->o_next = last->o_next;\n\tlast->o_next = nn;\n\tlast = nn;\n\tif (debug) {\n\t  fputs(\"activated rule:\\n\", stderr);\n\t  printrule(nn, stderr);\n\t}\n      }\n      if (debug)\n\tfputs(\"\\n\", stderr);\n      /* step back to allow (shorter) activated rules to match\n         in the order they appear */\n      while (--lines && r->l_prev)\n\tr = r->l_prev;\n      global_again = 1;\t\t/* signalize changes */\n      continue;\n    }\n\n    /* fire the rule */\n    r = rep(c, r->l_next, o->o_new, vars);\n    activerule = 0;\n    return r;\n  }\n  activerule = 0;\n  return r->l_next;\n}\n\n/* #define _TESTING */\n\nvoid usage(char *name) {\n  fprintf(stderr, \"Usage: %s [-D] [-o output] input rulesfile\\n\", name);\n  exit(1);\n}\n\n/* main - peephole optimizer */\nint main(int argc, char **argv) {\n  FILE *fp, *infile, *outfile = stdout;\n  int pass, option;\n  struct lnode head, *p, tail;\n\n  opts = NULL;\n  activerule = NULL;\n  htab[0]= NULL;\n\n  if (argc < 3)\n    usage(argv[0]);\n\n  while ((option = getopt(argc, argv, \"Do:\")) != -1) {\n    switch (option) {\n    case 'D':\n      debug = 1;\n      break;\n    case 'o':\n      outfile = fopen(optarg, \"w\");\n      if (outfile == NULL) {\n\tfprintf(stderr, \"Unable to write to %s\\n\", optarg);\n\texit(1);\n      }\n      break;\n    default:\n      usage(argv[0]);\n    }\n  }\n\n  // Open the input file\n  if ((infile = fopen(argv[optind], \"r\")) == NULL) {\n    fprintf(stderr, \"Can't open input file %s\\n\", argv[optind]);\n    exit(1);\n  }\n  // Get the patterns file\n  if ((fp = fopen(argv[optind + 1], \"r\")) == NULL) {\n    fprintf(stderr, \"Can't open patterns file %s\\n\", argv[optind + 1]);\n    exit(1);\n  }\n  init(fp);\n\n  getlst(infile, \"\", &head, &tail);\n\n  head.l_text = tail.l_text = \"\";\n\n  pass = 0;\n  do {\n    ++pass;\n    if (debug)\n      fprintf(stderr, \"\\n--- pass %d ---\\n\", pass);\n    global_again = 0;\n    for (p = head.l_next; p != &tail; p = opt(p));\n  } while (global_again && pass < MAX_PASS);\n\n  if (global_again) {\n    fprintf(stderr, \"error: maximum of %d passes exceeded\\n\", MAX_PASS);\n    error(\"       check for recursive substitutions\");\n  }\n\n  printlines(head.l_next, &tail, outfile);\n  exit(0);\n  return 1;\t\t\t/* make compiler happy */\n}\n\n#define STACKSIZE 20\n\nint sp;\nint stack[STACKSIZE];\n\nvoid push(int l) {\n  if (sp < STACKSIZE)\n    stack[sp++] = l;\n  ;\n}\n\nint pop(void) {\n  if (sp > 0)\n    return stack[--sp];\n  return 0;\n}\n\nint top(void) {\n  if (sp > 0)\n    return stack[sp - 1];\n  return 0;\n}\n\nint rpn_eval(char *expr, char **vars) {\n  char *ptr = expr;\n  char *endptr;\n  int op2;\n  int n;\n\n  sp = 0;\n\n  while (*ptr) {\n    switch (*ptr++) {\n    case '0':\n    case '1':\n    case '2':\n    case '3':\n    case '4':\n    case '5':\n    case '6':\n    case '7':\n    case '8':\n    case '9':\n      n = strtol(ptr - 1, &endptr, 0);\n      if (endptr == ptr - 1) {\n\tfprintf(stderr, \"Optimiser error, cannot parse number: %s\\n\",\n\t\tptr - 1);\n\texit(1);\n      }\n      ptr = endptr;\n      push(n);\n      break;\n    case '+':\n      {\n\tint a = pop();\n\tint b = pop();\n\tint c = a + b;\n\tpush(c);\n      }\n      break;\n    case '*':\n      push(pop() * pop());\n      break;\n    case '-':\n      op2 = pop();\n      push(pop() - op2);\n      break;\n    case '|':\n      op2 = pop();\n      push(pop() | op2);\n      break;\n    case '&':\n      op2 = pop();\n      push(pop() & op2);\n      break;\n    case '>':\n      op2 = pop();\n      push(pop() >> op2);\n      break;\n    case '<':\n      op2 = pop();\n      push(pop() << op2);\n      break;\n    case '/':\n      op2 = pop();\n      if (op2 != 0)\n\tpush(pop() / op2);\n      else\n\treturn 0;\t\t// Divide by zero\n      break;\n    case '%':\n      if (isdigit(*ptr)) {\n\t// It's a variable\n\tchar v = *ptr++;\n\tchar *endpt2;\n\tchar *val = vars[v - '0'];\n\tn = strtol(val, &endpt2, 0);\n\tif (endpt2 == val) {\n\t  fprintf(stderr, \"Optimiser error, cannot parse variable: %s\\n\",\n\t\t  val);\n\t  exit(1);\n\t}\n\tpush(n);\n      } else if (*ptr++ == '%') {\n\top2 = pop();\n\tif (op2 != 0) {\n\t  push(pop() % op2);\n\t} else {\n\t  return 0;\t\t// Divide by zero\n\t}\n      }\n      break;\n    }\n  }\n  if (sp != 1) {\n    int i;\n    fprintf(stderr, \"Exiting with a stack level of %d\\n\", sp);\n    for (i = 0; i < sp; i++) {\n      fprintf(stderr, \"Stack level %d -> %d\\n\", i, stack[i]);\n    }\n  }\n  return top();\n}\n"
  },
  {
    "path": "64_6809_Target/data.h",
    "content": "#ifndef extern_\n#define extern_ extern\n#endif\n\n// Global variables\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nextern_ int Line;\t\t     \t// Current line number\nextern_ int Linestart;\t\t     \t// True if at start of a line\nextern_ int Putback;\t\t     \t// Character put back by scanner\nextern_ struct symtable *Functionid; \t// Symbol ptr of the current function\nextern_ FILE *Infile;\t\t     \t// Input and output files\nextern_ FILE *Outfile;\nextern_ FILE *Symfile;\t\t\t// Symbol table file\nextern_ FILE *Idxfile;\t\t\t// AST offset index file\nextern_ char *Infilename;\t\t// Name of file we are parsing\nextern_ struct token Token;\t\t// Last token scanned\nextern_ struct token Peektoken;\t\t// A look-ahead token\nextern_ char Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern_ int Looplevel;\t\t\t// Depth of nested loops\nextern_ int Switchlevel;\t\t// Depth of nested switches\nextern char *Tstring[];\t\t\t// List of token strings\n"
  },
  {
    "path": "64_6809_Target/decl.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"expr.h\"\n#include \"gen.h\"\n#include \"misc.h\"\n#include \"opt.h\"\n#include \"parse.h\"\n#include \"stmt.h\"\n#include \"sym.h\"\n#include \"target.h\"\n#include \"tree.h\"\n#include \"types.h\"\n\n// Parsing of declarations\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nstatic struct symtable *composite_declaration(int type);\nstatic int typedef_declaration(struct symtable **ctype);\nstatic int type_of_typedef(char *name, struct symtable **ctype);\nstatic void enum_declaration(void);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2, struct ASTnode **gluetree);\n\n// Parse the current token and return a primitive type enum value,\n// a pointer to any composite type and possibly modify\n// the class of the type.\nint parse_type(struct symtable **ctype, int *class) {\n  int type = 0, exstatic = 1;\n  *ctype=NULL;\n\n  // See if the visibility class has been changed to extern or static\n  while (exstatic) {\n    switch (Token.token) {\n      case T_EXTERN:\n\tif (*class == V_STATIC)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = V_EXTERN;\n\tscan(&Token);\n\tbreak;\n      case T_STATIC:\n\tif (*class == V_LOCAL)\n\t  fatal(\"Compiler doesn't support static local declarations\");\n\tif (*class == V_EXTERN)\n\t  fatal(\"Illegal to have extern and static at the same time\");\n\t*class = V_STATIC;\n\tscan(&Token);\n\tbreak;\n      default:\n\texstatic = 0;\n    }\n  }\n\n  // Now work on the actual type keyword\n  switch (Token.token) {\n    case T_VOID:\n      type = P_VOID;\n      scan(&Token);\n      break;\n    case T_CHAR:\n      type = P_CHAR;\n      scan(&Token);\n      break;\n    case T_INT:\n      type = P_INT;\n      scan(&Token);\n      break;\n    case T_LONG:\n      type = P_LONG;\n      scan(&Token);\n      break;\n\n      // For the following, if we have a ';' after the\n      // parsing then there is no type, so return -1.\n      // Example: struct x {int y; int z};\n    case T_STRUCT:\n      type = P_STRUCT;\n      *ctype = composite_declaration(P_STRUCT);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_UNION:\n      type = P_UNION;\n      *ctype = composite_declaration(P_UNION);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_ENUM:\n      type = P_INT;\t\t// Enums are really ints\n      enum_declaration();\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_TYPEDEF:\n      type = typedef_declaration(ctype);\n      if (Token.token == T_SEMI)\n\ttype = -1;\n      break;\n    case T_IDENT:\n      type = type_of_typedef(Text, ctype);\n      break;\n    default:\n      fatals(\"Illegal type, token\", Tstring[Token.token]);\n  }\n  return (type);\n}\n\n// Given a type parsed by parse_type(), scan in any following\n// '*' tokens and return the new type\nint parse_stars(int type) {\n\n  while (1) {\n    if (Token.token != T_STAR)\n      break;\n    type = pointer_to(type);\n    scan(&Token);\n  }\n  return (type);\n}\n\n// Parse a type which appears inside a cast\nint parse_cast(struct symtable **ctype) {\n  int type = 0, class = 0;\n\n  // Get the type inside the parentheses\n  type = parse_stars(parse_type(ctype, &class));\n\n  // Do some error checking. I'm sure more can be done\n  if (type == P_STRUCT || type == P_UNION || type == P_VOID)\n    fatal(\"Cannot cast to a struct, union or void type\");\n  return (type);\n}\n\n// Given a type, parse an expression of literals and ensure\n// that the type of this expression matches the given type.\n// Parse any type cast that precedes the expression.\n// If an integer literal, return this value.\n// If a string literal, return the label number of the string.\nint parse_literal(int type) {\n  struct ASTnode *tree;\n  struct symtable *sym;\n\n  // Parse the expression and optimise the resulting AST tree\n  tree = optimise(binexpr(0));\n\n  // If there's a cast, get the child and\n  // mark it as having the type from the cast\n  if (tree->op == A_CAST) {\n    tree->left->type = tree->type;\n    tree = tree->left;\n  }\n\n  // The tree must now have an integer or string literal\n  if (tree->op != A_INTLIT && tree->op != A_STRLIT)\n    fatal(\"Cannot initialise globals with a general expression\");\n\n  // Deal with pointer to literals\n  if (ptrtype(type)) {\n    // If the type is char * and we have a string literal\n    if (type == pointer_to(P_CHAR) && tree->op == A_STRLIT) {\n      // Add it to the string literal symbol\n      // table and return the symbol's id\n      sym= addglob(tree->name, type, NULL, S_STRLIT, V_GLOBAL, 0, 0);\n      return (sym->id);\n    }\n\n    // We have a zero int literal, so that's a NULL\n    if (tree->op == A_INTLIT && tree->a_intvalue == 0)\n      return (0);\n  }\n\n  // We only get here with an integer literal.\n  // If the tree is an A_INTLIT and the left type is P_CHAR,\n  // and the INTLIT is in the range 0 to 255, change the trees's\n  // type to PCHAR to ensure we can do the assignment\n  if ((tree->op == A_INTLIT) && (type == P_CHAR) &&\n          (tree->a_intvalue >= 0) && (tree->a_intvalue < 256))\n        tree->type = P_CHAR;\n\n  // Check that the input type is an integer type\n  // and is wide enough to hold the literal value\n  if (inttype(type) && typesize(type, NULL) >= typesize(tree->type, NULL))\n    return (tree->a_intvalue);\n\n  fatal(\"Type mismatch: literal vs. variable\");\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Given a pointer to a symbol that may already exist\n// return true if this symbol doesn't exist. We use\n// this function to convert externs into globals\nstatic int is_new_symbol(struct symtable *sym, int class,\n\t\t\t int type, struct symtable *ctype) {\n\n  // There is no existing symbol, thus is new\n  if (sym == NULL)\n    return (1);\n\n  // global versus extern: if they match that it's not new\n  // and we can convert the class to global\n  if ((sym->class == V_GLOBAL && class == V_EXTERN)\n      || (sym->class == V_EXTERN && class == V_GLOBAL)) {\n\n    // If the types don't match, there's a problem\n    if (type != sym->type)\n      fatals(\"Type mismatch between global/extern\", sym->name);\n\n    // Struct/unions, also compare the ctype\n    if (type >= P_STRUCT && ctype != sym->ctype)\n      fatals(\"Type mismatch between global/extern\", sym->name);\n\n    // If we get to here, the types match, so mark the symbol\n    // as global\n    sym->class = V_GLOBAL;\n    // Return that symbol is not new\n    return (0);\n  }\n  // It must be a duplicate symbol if we get here\n  fatals(\"Duplicate global variable declaration\", sym->name);\n  return (-1);\t\t\t// Keep -Wall happy\n}\n\n// Given the type, name and class of a scalar variable,\n// parse any initialisation value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *scalar_declaration(char *varname, int type,\n\t\t\t\t\t   struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  struct ASTnode *varnode, *exprnode;\n  *tree = NULL;\n\n  // Add this as a known scalar\n  switch (class) {\n    case V_STATIC:\n    case V_EXTERN:\n    case V_GLOBAL:\n      // See if this variable is new or already exists\n      sym = findSymbol(varname, S_NOTATYPE, 0);\n      if (is_new_symbol(sym, class, type, ctype))\n\tsym = addglob(varname, type, ctype, S_VARIABLE, class, 1, 0);\n      break;\n    case V_LOCAL:\n      sym = addmemb(varname, type, ctype, V_LOCAL, S_VARIABLE, 1);\n      break;\n    case V_PARAM:\n      sym = addmemb(varname, type, ctype, V_PARAM, S_VARIABLE, 1);\n      break;\n    case V_MEMBER:\n      sym = addmemb(varname, type, ctype, V_MEMBER, S_VARIABLE, 1);\n      break;\n  }\n\n  // The variable is being initialised\n  if (Token.token == T_ASSIGN) {\n    // Only possible for a global or local\n    if (class != V_GLOBAL && class != V_LOCAL && class != V_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Globals must be assigned a literal value\n    if (class == V_GLOBAL || class == V_STATIC) {\n      // Create one initial value for the variable and\n      // parse this value\n      sym->initlist = (int *) malloc(sizeof(int));\n      sym->initlist[0] = parse_literal(type);\n    }\n    if (class == V_LOCAL) {\n      // Make an A_IDENT AST node with the variable\n      varnode = mkastleaf(A_IDENT, sym->type, sym->ctype, sym, 0);\n\n      // Get the expression for the assignment, make into a rvalue\n      exprnode = binexpr(0);\n      exprnode->rvalue = 1;\n\n      // If the exprnode is an A_INTLIT and the variable type is P_CHAR,\n      // and the INTLIT is in the range 0 to 255, change the exprnode's\n      // type to PCHAR to ensure we can do the assignment\n      if ((exprnode->op == A_INTLIT) && (varnode->type == P_CHAR) &&\n          (exprnode->a_intvalue >= 0) && (exprnode->a_intvalue < 256))\n        exprnode->type = P_CHAR;\n\n      // Ensure the expression's type matches the variable\n      exprnode = modify_type(exprnode, varnode->type, varnode->ctype, 0);\n      if (exprnode == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree\n      *tree = mkastnode(A_ASSIGN, exprnode->type, exprnode->ctype, exprnode,\n\t\t\tNULL, varnode, NULL, 0);\n    }\n  }\n\n  return (sym);\n}\n\n// Given the type, name and class of an array variable, parse\n// the size of the array, if any. Then parse any initialisation\n// value and allocate storage for it.\n// Return the variable's symbol table entry.\nstatic struct symtable *array_declaration(char *varname, int type,\n\t\t\t\t\t  struct symtable *ctype, int class) {\n\n  struct symtable *sym = NULL;\t// New symbol table entry\n  int nelems = -1;\t\t// Assume the number of elements won't be given\n  int maxelems;\t\t\t// The maximum number of elements in the init list\n  int *initlist;\t\t// The list of initial elements \n  int i = 0, j;\n\n  // Skip past the '['\n  scan(&Token);\n\n  // See if we have an array size\n  if (Token.token != T_RBRACKET) {\n    nelems = parse_literal(P_INT);\n    if (nelems <= 0)\n      fatald(\"Array size is illegal\", nelems);\n  }\n  // Ensure we have a following ']'\n  match(T_RBRACKET, \"]\");\n\n  // Add this as a known array. We treat the\n  // array as a pointer to its elements' type\n  switch (class) {\n    case V_STATIC:\n    case V_EXTERN:\n    case V_GLOBAL:\n      // See if this variable is new or already exists\n      sym = findSymbol(varname, S_NOTATYPE, 0);\n      if (is_new_symbol(sym, class, pointer_to(type), ctype))\n\tsym = addglob(varname, pointer_to(type), ctype, S_ARRAY, class, 0, 0);\n      break;\n    case V_LOCAL:\n      // Add the array to the local symbol table.\n      sym = addmemb(varname, pointer_to(type), ctype, V_LOCAL, S_ARRAY, 0);\n      sym->st_hasaddr = 1;\n      break;\n    default:\n      fatal(\"Declaration of array parameters is not implemented\");\n  }\n\n  // Array initialisation\n  if (Token.token == T_ASSIGN) {\n    if (class != V_GLOBAL && class != V_STATIC)\n      fatals(\"Variable can not be initialised\", varname);\n    scan(&Token);\n\n    // Get the following left curly bracket\n    match(T_LBRACE, \"{\");\n\n#define TABLE_INCREMENT 10\n\n    // If the array already has nelems, allocate that many elements\n    // in the list. Otherwise, start with TABLE_INCREMENT.\n    if (nelems != -1)\n      maxelems = nelems;\n    else\n      maxelems = TABLE_INCREMENT;\n    initlist = (int *) malloc(maxelems * sizeof(int));\n\n    // Loop getting a new literal value from the list\n    while (1) {\n\n      // Check we can add the next value, then parse and add it\n      if (nelems != -1 && i == maxelems)\n\tfatal(\"Too many values in initialisation list\");\n\n      initlist[i++] = parse_literal(type);\n\n      // Increase the list size if the original size was\n      // not set and we have hit the end of the current list\n      if (nelems == -1 && i == maxelems) {\n\tmaxelems += TABLE_INCREMENT;\n\tinitlist = (int *) realloc(initlist, maxelems * sizeof(int));\n      }\n      // Leave when we hit the right curly bracket\n      if (Token.token == T_RBRACE) {\n\tscan(&Token);\n\tbreak;\n      }\n      // Next token must be a comma, then\n      comma();\n    }\n\n    // Zero any unused elements in the initlist.\n    // Attach the list to the symbol table entry\n    for (j = i; j < sym->nelems; j++)\n      initlist[j] = 0;\n\n    if (i > nelems)\n      nelems = i;\n    sym->initlist = initlist;\n  }\n  // Set the size of the array and the number of elements\n  // Only externs can have no elements.\n  if (class != V_EXTERN && nelems <= 0)\n    fatals(\"Array must have non-zero elements\", sym->name);\n\n  sym->nelems = nelems;\n  sym->size = sym->nelems * typesize(type, ctype);\n\n  return (sym);\n}\n\n// Given a pointer to the new function being declared and\n// a possibly NULL pointer to the function's previous declaration,\n// parse a list of parameters and cross-check them against the\n// previous declaration. Return the count of parameters\nstatic int param_declaration_list(struct symtable *oldfuncsym,\n\t\t\t\t  struct symtable *newfuncsym) {\n  int type, paramcnt = 0;\n  struct symtable *ctype;\n  struct symtable *protoptr = NULL;\n  struct ASTnode *unused;\n\n  // Get the pointer to the first prototype parameter\n  if (oldfuncsym != NULL)\n    protoptr = oldfuncsym->member;\n\n  // Loop getting any parameters\n  while (Token.token != T_RPAREN) {\n\n    // If the first token is 'void'\n    if (Token.token == T_VOID) {\n      // Peek at the next token. If a ')', the function\n      // has no parameters, so leave the loop.\n      scan(&Peektoken);\n      if (Peektoken.token == T_RPAREN) {\n\t// Move the Peektoken into the Token\n\tparamcnt = 0;\n\tscan(&Token);\n\tbreak;\n      }\n    }\n\n    // If an ellipsis (...), mark the function as such\n    if (Token.token == T_ELLIPSIS) {\n      newfuncsym->has_ellipsis= 1;\n\n      // This must be the last parameter, so expect a ')'\n      scan(&Token);\n      if (Token.token != T_RPAREN)\n        fatal(\"Expecting right parenthesis after ellipsis\");\n      // Leave the parameter loop\n      break;\n    }\n\n    // Get the type of the next parameter\n    type = declaration_list(&ctype, V_PARAM, T_COMMA, T_RPAREN, &unused);\n    if (type == -1)\n      fatal(\"Bad type in parameter list\");\n\n    if (protoptr != NULL) {\n      // Ensure the type of this parameter matches the prototype\n      if (type != protoptr->type) {\n\tfatald(\"Type doesn't match prototype for parameter\", paramcnt + 1);\n      }\n\n      // Ensure the old/new parameter names also match\n      if (strcmp(Text, protoptr->name)) {\n\tfatals(\"New parameter name doesn't match prototype\", Text);\n      }\n\n      protoptr = protoptr->next;\n    }\n    paramcnt++;\n\n    // Stop when we hit the right parenthesis\n    if (Token.token == T_RPAREN)\n      break;\n    // We need a comma as separator\n    comma();\n  }\n\n  if (oldfuncsym != NULL && paramcnt != oldfuncsym->nelems)\n    fatals(\"Parameter count mismatch for function\", oldfuncsym->name);\n\n  // Return the count of parameters\n  return (paramcnt);\n}\n\n//\n// function_declaration: type identifier '(' parameter_list ')' ;\n//      | type identifier '(' parameter_list ')' compound_statement   ;\n//\n// Parse the declaration of function.\nstatic struct symtable *function_declaration(char *funcname, int type,\n\t\t\t\t\t     struct symtable *ctype,\n\t\t\t\t\t     int class) {\n  struct ASTnode *tree;\n  struct symtable *oldfuncsym, *newfuncsym = NULL;\n  int endlabel = 0, paramcnt;\n  int linenum = Line;\n\n  // Search for an existing symbol with this name\n  // and point oldfuncsym at it, or NULL.\n  if ((oldfuncsym = findSymbol(funcname, S_NOTATYPE, 0)) != NULL)\n    if (oldfuncsym->stype != S_FUNCTION)\n      oldfuncsym = NULL;\n\n  // Add the function to the symbol table.\n  // Assumption: functions only return scalar types, so NULL below\n  newfuncsym = addglob(funcname, type, NULL, S_FUNCTION, class, 0, 0);\n  newfuncsym->has_ellipsis=0;\t\t// Assume no ellipsis for now\n\n  // NULL the global Functionid so that we don't try to match this\n  // function's parameters against the ones in the previous function\n  Functionid= NULL;\n\n  // Scan in the '(', any parameters and the ')'.\n  // Pass in any existing function prototype pointer\n  lparen();\n  paramcnt = param_declaration_list(oldfuncsym, newfuncsym);\n  rparen();\n\n  // If this is a new function declaration, update the\n  // function symbol entry with the number of parameters.\n  // Also copy the parameter list into the function's node.\n  if (newfuncsym) {\n    newfuncsym->nelems = paramcnt;\n    oldfuncsym = newfuncsym;\n  }\n\n  // If the declaration ends in a semicolon, only a prototype.\n  if (Token.token == T_SEMI) {\n    return (oldfuncsym);\n  }\n\n  // This is not just a prototype.\n  // Set the Functionid global to the function's symbol pointer\n  Functionid = oldfuncsym;\n\n  // Get the AST tree for the compound statement and mark\n  // that we have parsed no loops or switches yet\n  Looplevel = 0;\n  Switchlevel = 0;\n  lbrace();\n  tree = compound_statement(0);\n  rbrace();\n\n  // If the function type isn't P_VOID ...\n  if (type != P_VOID) {\n\n    // Error if no statements in the function\n    if (tree == NULL)\n      fatal(\"No statements in function with non-void type\");\n\n    // Check that the last AST operation in the\n    // compound statement was a return statement\n    // NOTE! Because we have free'd the tree,\n    // we can't do this any more\n#if 0\n    finalstmt = (tree->op == A_GLUE) ? tree->right : tree;\n    if (finalstmt == NULL || finalstmt->op != A_RETURN)\n      fatal(\"No return for function with non-void type\");\n#endif\n  }\n\n  // Build the A_FUNCTION node which has the function's symbol pointer\n  // and the compound statement sub-tree\n  tree = mkastunary(A_FUNCTION, type, ctype, tree, oldfuncsym, endlabel);\n  tree->linenum = linenum;\n\n  // Do optimisations on the AST tree\n  // WAS tree = optimise(tree);\n\n  // Serialise the tree\n  serialiseAST(tree);\n  freetree(tree, 0);\n\n  // Flush out the in-memory symbol table.\n  // We are no longer in a function.\n  flushSymtable();\n  Functionid= NULL;\n\n  return (oldfuncsym);\n}\n\n// Parse composite type declarations: structs or unions.\n// Either find an existing struct/union declaration, or build\n// a struct/union symbol table entry and return its pointer.\nstatic struct symtable *composite_declaration(int type) {\n  struct symtable *ctype = NULL;\n  struct symtable *m;\n  struct ASTnode *unused;\n  int offset;\n  int t;\n\n  // Skip the struct/union keyword\n  scan(&Token);\n\n  // See if there is a following struct/union name\n  if (Token.token == T_IDENT) {\n    // Find any matching composite type\n    if (type == P_STRUCT)\n      ctype = findstruct(Text);\n    else\n      ctype = findunion(Text);\n    scan(&Token);\n  }\n  // If the next token isn't an LBRACE , this is\n  // the usage of an existing struct/union type.\n  // Return the pointer to the type.\n  if (Token.token != T_LBRACE) {\n    if (ctype == NULL)\n      fatals(\"unknown struct/union type\", Text);\n    return (ctype);\n  }\n  // Ensure this struct/union type hasn't been\n  // previously defined\n  if (ctype)\n    fatals(\"previously defined struct/union\", Text);\n\n  // Build the composite type and skip the left brace\n  if (type == P_STRUCT)\n    ctype = addtype(Text, P_STRUCT, NULL, S_STRUCT, V_GLOBAL, 0, 0);\n  else\n    ctype = addtype(Text, P_UNION, NULL, S_UNION, V_GLOBAL, 0, 0);\n  scan(&Token);\n\n  // Scan in the list of members\n  while (1) {\n    // Get the next member. m is used as a dummy\n    t = declaration_list(&m, V_MEMBER, T_SEMI, T_RBRACE, &unused);\n    if (t == -1)\n      fatal(\"Bad type in member list\");\n    if (Token.token == T_SEMI)\n      scan(&Token);\n    if (Token.token == T_RBRACE)\n      break;\n  }\n\n  // Find the closing parenthesis\n  rbrace();\n\n  // Set the offset of the initial member\n  // and find the first free byte after it\n  m = ctype->member;\n  m->st_posn = 0;\n  offset = typesize(m->type, m->ctype);\n\n  // Set the position of each successive member in the composite type\n  // Unions are easy. For structs, align the member and find the next free byte\n  for (m = m->next; m != NULL; m = m->next) {\n    // Set the offset for this member\n    if (type == P_STRUCT)\n      m->st_posn = genalign(m->type, offset, 1);\n    else\n      m->st_posn = 0;\n\n    // Get the offset of the next free byte after this member\n    offset += typesize(m->type, m->ctype);\n  }\n\n  // Set the overall size of the composite type\n  ctype->size = offset;\n  return (ctype);\n}\n\n// Parse an enum declaration\nstatic void enum_declaration(void) {\n  struct symtable *etype = NULL;\n  char *name = NULL;\n  int intval = 0;\n\n  // Skip the enum keyword.\n  scan(&Token);\n\n  // If there's a following enum type name, get a\n  // pointer to any existing enum type node.\n  if (Token.token == T_IDENT) {\n    etype = findenumtype(Text);\n    name = strdup(Text);\t// As it gets tromped soon\n    scan(&Token);\n  }\n  // If the next token isn't a LBRACE, check\n  // that we have an enum type name, then return\n  if (Token.token != T_LBRACE) {\n    if (etype == NULL)\n      fatals(\"undeclared enum type:\", name);\n    return;\n  }\n  // We do have an LBRACE. Skip it\n  scan(&Token);\n\n  // If we have an enum type name, ensure that it\n  // hasn't been declared before.\n  if (etype != NULL)\n    fatals(\"enum type redeclared:\", etype->name);\n\n  // Build an enum type node for this identifier\n  // if there is a name\n  if (name!=NULL) {\n    etype = addtype(name, P_INT, NULL, S_ENUMTYPE, V_GLOBAL, 0, 0);\n    free(name);\n  }\n\n  // Loop to get all the enum values\n  while (1) {\n    // Ensure we have an identifier\n    // Copy it in case there's an int literal coming up\n    ident();\n    name = strdup(Text);\n\n    // Ensure this enum value hasn't been declared before\n    etype = findenumval(name);\n    if (etype != NULL)\n      fatals(\"enum value redeclared:\", name);\n\n    // If the next token is an '=', skip it and\n    // get the following int literal\n    if (Token.token == T_ASSIGN) {\n      scan(&Token);\n      if ((Token.token != T_INTLIT) && (Token.token != T_CHARLIT))\n\tfatal(\"Expected int literal after '='\");\n      intval = Token.intvalue;\n      scan(&Token);\n    }\n    // Build an enum value node for this identifier.\n    // Increment the value for the next enum identifier.\n    etype = addglob(name, P_INT, NULL, S_ENUMVAL, V_GLOBAL, 0, intval++);\n\n    free(name);\n\n    // Bail out on a right curly bracket, else get a comma\n    if (Token.token == T_RBRACE)\n      break;\n    comma();\n  }\n  scan(&Token);\t\t\t// Skip over the right curly bracket\n}\n\n// Parse a typedef declaration and return the type\n// and ctype that it represents\nstatic int typedef_declaration(struct symtable **ctype) {\n  int type, class = 0;\n\n  // Skip the typedef keyword.\n  scan(&Token);\n\n  // Get the actual type following the keyword\n  type = parse_type(ctype, &class);\n  if (class != 0)\n    fatal(\"Can't have static/extern in a typedef declaration\");\n\n  // Get any following '*' tokens\n  type = parse_stars(type);\n\n  // See if the typedef identifier already exists\n  if (findtypedef(Text) != NULL)\n    fatals(\"redefinition of typedef\", Text);\n\n  // It doesn't exist so add it to the type list\n  addtype(Text, type, *ctype, S_TYPEDEF, class, 0, 0);\n  scan(&Token);\n  return (type);\n}\n\n// Given a typedef name, return the type it represents\nstatic int type_of_typedef(char *name, struct symtable **ctype) {\n  struct symtable *t;\n\n  // Look up the typedef in the list\n  t = findtypedef(name);\n  if (t == NULL)\n    fatals(\"unknown type\", name);\n  scan(&Token);\n  *ctype = t->ctype;\n  return (t->type);\n}\n\n// Parse the declaration of a variable or function.\n// The type and any following '*'s have been scanned, and we\n// have the identifier in the Token variable.\n// The class argument is the symbol's class.\n// Return a pointer to the symbol's entry in the symbol table\nstatic struct symtable *symbol_declaration(int type, struct symtable *ctype,\n\t\t\t\t\t   int class, struct ASTnode **tree) {\n  struct symtable *sym = NULL;\n  char *varname = strdup(Text);\n\n  // Ensure that we have an identifier. \n  // We copied it above so we can scan more tokens in, e.g.\n  // an assignment expression for a local variable.\n  ident();\n\n  // Deal with function declarations\n  if (Token.token == T_LPAREN) {\n    sym= function_declaration(varname, type, ctype, class);\n    free(varname);\n    return(sym);\n  }\n\n  // See if this array or scalar variable has already been declared\n  switch (class) {\n    case V_EXTERN:\n    case V_STATIC:\n    case V_GLOBAL:\n    case V_LOCAL:\n    case V_PARAM:\n      if (findlocl(varname, 0) != NULL)\n\tfatals(\"Duplicate local variable declaration\", varname);\n      break;\n    case V_MEMBER:\n      if (findmember(varname) != NULL)\n\tfatals(\"Duplicate struct/union member declaration\", varname);\n  }\n\n  // Add the array or scalar variable to the symbol table\n  if (Token.token == T_LBRACKET) {\n    sym = array_declaration(varname, type, ctype, class);\n    *tree = NULL;\t\t// Local arrays are not initialised\n  } else\n    sym = scalar_declaration(varname, type, ctype, class, tree);\n  free(varname);\n  return (sym);\n}\n\n// Parse a list of symbols where there is an initial type.\n// Return the type of the symbols. et1 and et2 are end tokens.\nint declaration_list(struct symtable **ctype, int class, int et1, int et2,\n\t\t     struct ASTnode **gluetree) {\n  int inittype, type;\n  struct symtable *sym;\n  struct ASTnode *tree = NULL;\n  *gluetree = NULL;\n\n  // Get the initial type. If -1, it was\n  // a composite type definition, return this\n  if ((inittype = parse_type(ctype, &class)) == -1)\n    return (inittype);\n\n  // Now parse the list of symbols\n  while (1) {\n    // See if this symbol is a pointer\n    type = parse_stars(inittype);\n\n    // Parse this symbol\n    sym = symbol_declaration(type, *ctype, class, &tree);\n\n    // We parsed a function, there is no list so leave\n    if (sym->stype == S_FUNCTION) {\n      if (class != V_GLOBAL && class != V_STATIC)\n\tfatal(\"Function definition not at global level\");\n      return (type);\n    }\n    // Glue any AST tree from a local declaration\n    // to build a sequence of assignments to perform\n    if (*gluetree == NULL)\n      *gluetree = tree;\n    else\n      *gluetree =\n\tmkastnode(A_GLUE, P_NONE, NULL, *gluetree, NULL, tree, NULL, 0);\n\n    // We are at the end of the list, leave\n    if (Token.token == et1 || Token.token == et2)\n      return (type);\n\n    // Otherwise, we need a comma as separator\n    comma();\n  }\n\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Parse one or more global declarations,\n// either variables, functions or structs\nvoid global_declarations(void) {\n  struct symtable *ctype = NULL;\n  struct ASTnode *unused;\n\n  // Loop parsing one declaration list until the end of file\n  while (Token.token != T_EOF) {\n    declaration_list(&ctype, V_GLOBAL, T_SEMI, T_EOF, &unused);\n\n    // Skip any separating semicolons\n    if (Token.token == T_SEMI)\n      scan(&Token);\n  }\n}\n"
  },
  {
    "path": "64_6809_Target/decl.h",
    "content": "/* decl.c */\nint parse_type(struct symtable **ctype, int *class);\nint parse_stars(int type);\nint parse_cast(struct symtable **ctype);\nint parse_literal(int type);\nint declaration_list(struct symtable **ctype, int class, int et1, int et2, struct ASTnode **gluetree);\nvoid global_declarations(void);\n"
  },
  {
    "path": "64_6809_Target/defs.h",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n\n// Structure and enum definitions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nenum {\n  TEXTLEN = 512\t\t\t// Length of identifiers in input\n};\n\n// Commands and default filenames\n#define AOUT \"a.out\"\n#define ASCMD \"as6809 -o \"\n#define LDCMD \"ld6809 -o %s /tmp/crt0.o %s /opt/fcc/lib/6809/libc.a /opt/fcc/lib/6809/lib6809.a -m %s.map\"\n#define CPPCMD \"cpp -nostdinc -isystem \"\n\n// Token types\nenum {\n  T_EOF,\n\n  // Binary operators\n  T_ASSIGN, T_ASPLUS, T_ASMINUS,                // 1\n  T_ASSTAR, T_ASSLASH, T_ASMOD,                 // 4\n  T_QUESTION, T_LOGOR, T_LOGAND,                // 7\n  T_OR, T_XOR, T_AMPER,                         // 10\n  T_EQ, T_NE,                                   // 13\n  T_LT, T_GT, T_LE, T_GE,                       // 15\n  T_LSHIFT, T_RSHIFT,                           // 19\n  T_PLUS, T_MINUS, T_STAR, T_SLASH, T_MOD,      // 21\n\n  // Other operators\n  T_INC, T_DEC, T_INVERT, T_LOGNOT,             // 26\n\n  // Type keywords\n  T_VOID, T_CHAR, T_INT, T_LONG,                // 30\n\n  // Other keywords\n  T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN,       // 34\n  T_STRUCT, T_UNION, T_ENUM, T_TYPEDEF,         // 39\n  T_EXTERN, T_BREAK, T_CONTINUE, T_SWITCH,      // 43\n  T_CASE, T_DEFAULT, T_SIZEOF, T_STATIC,        // 47\n\n  // Structural tokens\n  T_INTLIT, T_STRLIT, T_SEMI, T_IDENT,          // 51\n  T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN,       // 55\n  T_LBRACKET, T_RBRACKET, T_COMMA, T_DOT,       // 59\n  T_ARROW, T_COLON, T_ELLIPSIS, T_CHARLIT,      // 63\n\n  // Misc\n  T_FILENAME, T_LINENUM\t\t\t\t// 67\n};\n\n// Token structure\nstruct token {\n  int token;\t\t\t// Token type, from the enum list above\n  char *tokstr;\t\t\t// String version of the token\n  int intvalue;\t\t\t// For T_INTLIT, the integer value\n};\n\n// AST node types. The first few line up\n// with the related tokens\nenum {\n  A_ASSIGN = 1, A_ASPLUS, A_ASMINUS, A_ASSTAR,\t\t\t//  1\n  A_ASSLASH, A_ASMOD, A_TERNARY, A_LOGOR,\t\t\t//  5\n  A_LOGAND, A_OR, A_XOR, A_AND, A_EQ, A_NE, A_LT,\t\t//  9\n  A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT,\t\t\t\t// 16\n  A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_MOD,\t\t// 21\n  A_INTLIT, A_STRLIT, A_IDENT, A_GLUE,\t\t\t\t// 26\n  A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN,\t\t\t// 30\n  A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE,\t\t\t\t// 35\n  A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC,\t\t\t// 39\n  A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL, A_BREAK,\t\t// 43\n  A_CONTINUE, A_SWITCH, A_CASE, A_DEFAULT, A_CAST\t\t// 48\n};\n\n// Primitive types. The bottom 4 bits is an integer\n// value that represents the level of indirection,\n// e.g. 0= no pointer, 1= pointer, 2= pointer pointer etc.\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\n// A symbol in the symbol table is\n// one of these structural types.\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY, S_ENUMVAL, S_STRLIT,\n  S_STRUCT, S_UNION, S_ENUMTYPE, S_TYPEDEF, S_NOTATYPE\n};\n\n// Visibilty class for symbols\nenum {\n  V_GLOBAL,\t\t\t// Globally visible symbol\n  V_EXTERN,\t\t\t// External globally visible symbol\n  V_STATIC,\t\t\t// Static symbol, visible in one file\n  V_LOCAL,\t\t\t// Locally visible symbol\n  V_PARAM,\t\t\t// Locally visible function parameter\n  V_MEMBER\t\t\t// Member of a struct or union\n};\n\n// Symbol table structure\nstruct symtable {\n  char *name;\t\t\t// Name of a symbol\n  int id;\t\t\t// Numeric id of the symbol\n  int type;\t\t\t// Primitive type for the symbol\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int ctypeid;\t\t\t// Numeric id of the struct/union type\n  int stype;\t\t\t// Structural type for the symbol\n  int class;\t\t\t// Visibility class for the symbol\n  int size;\t\t\t// Total size in bytes of this symbol\n                                // For functions: size 1 means ... (ellipsis)\n#define has_ellipsis size\n  int nelems;\t\t\t// Functions: # params. Arrays: # elements.\n  int st_hasaddr;\t\t// For locals, 1 if any A_ADDR operation\n#define st_endlabel st_posn\t// For functions, the end label\n#define st_label st_posn\t// For string literals, the associated label\n  int st_posn;\t\t\t// For locals, the negative offset\n    \t\t\t\t// from the stack base pointer.\n\t\t\t\t// For struct members, the offset of\n\t\t\t\t// the member from the base of the struct\n  int *initlist;\t\t// List of initial values\n  struct symtable *next;\t// Next symbol in the symbol table\n  struct symtable *member;\t// List of member of struct, union or enum.\n};\t\t\t\t// For functions, list of parameters & locals.\n\n// Abstract Syntax Tree structure\nstruct ASTnode {\n  int op;\t\t\t// \"Operation\" to be performed on this tree\n  int type;\t\t\t// Type of any expression this tree generates\n  struct symtable *ctype;\t// If struct/union, ptr to that type\n  int rvalue;\t\t\t// True if the node is an rvalue\n  struct ASTnode *left;\t\t// Left, middle and right child trees\n  struct ASTnode *mid;\n  struct ASTnode *right;\n  int nodeid;                   // Node id when tree is serialised\n  int leftid;                   // Numeric ids when serialised\n  int midid;\n  int rightid;\n  struct symtable *sym;\t\t// For many AST nodes, the pointer to\n  \t\t\t\t// the symbol in the symbol table\n  char *name;\t\t\t// The symbol's name (used by serialiser)\n  int symid;\t\t\t// Symbol's unique id (used by serialiser)\n#define a_intvalue a_size\t// For A_INTLIT, the integer value\n  int a_size;\t\t\t// For A_SCALE, the size to scale by\n  int linenum;\t\t\t// Line number from where this node comes\n};\n\nenum {\n  NOREG = -1,\t\t\t// Use NOREG when the AST generation\n  \t\t\t\t// functions have no register to return\n  NOLABEL = 0\t\t\t// Use NOLABEL when we have no label to\n    \t\t\t\t// pass to genAST()\n};\n"
  },
  {
    "path": "64_6809_Target/desym.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n\n// Symbol table deserialiser\n// Copyright (c) 2024 Warren Toomey, GPL3\n\n// Read at most count-1 characters from the\n// f FILE and store them in the s buffer.\n// Terminate the s buffer with a NUL.\n// Return NULL if unable to read or an EOF.\n// Else, return the original s pointer pointer.\nchar *fgetstr(char *s, size_t count, FILE * f) {\n  size_t i = count;\n  size_t err;\n  char ch;\n  char *ret = s;\n\n  while (i-- != 0) {\n    err= fread(&ch, 1, 1, f);\n    if (err!=1) {\n      if (s == ret)\n        return(NULL);\n      break;\n    }\n    *s++ = ch;\n    if (ch == 0)\n      break;\n  }\n  *s = 0;\n  return(ferror(f) ? (char *) NULL : ret);\n}\n\n// Read one symbol in. Return -1 if none.\nint deserialiseSym(struct symtable *sym, FILE *in) {\n  struct symtable *memb, *last;\n\n  // Read one symbol struct in from in\n  if (fread(sym, sizeof(struct symtable), 1, in)!=1)\n    return(-1);\n\n  // If the type is P_NONE, skip this one and read in\n  // another symbol. This marks the division between\n  // AST trees\n  if (sym->type==P_NONE) {\n    // Debug: printf(\"Skipping a P_NONE symbol\\n\");\n    if (fread(sym, sizeof(struct symtable), 1, in)!=1)\n      return(-1);\n  }\n\n  // Get the symbol name\n  if (sym->name != NULL) {\n    fgetstr(Text, TEXTLEN + 1, in);\n    sym->name= strdup(Text);\n  }\n\n  // Get any initial values\n  if (sym->initlist != NULL) {\n    sym->initlist= (int *)malloc(sym->nelems* sizeof(int));\n    fread(sym->initlist, sizeof(int), sym->nelems, in);\n  }\n\n  // If there are any members, read them in\n  if (sym->member != NULL) {\n    sym->member= last= NULL;\n\n    while (1) {\n      // Create an empty symbol struct\n      memb= (struct symtable *)malloc(sizeof(struct symtable));\n\n      // Read the struct in from the in file\n      // Stop if no symbols in the file\n      if (deserialiseSym(memb, in)== -1) return(0);\n\n      // Attach this to either the head or the last\n      if (sym->member==NULL) {\n        sym->member= last= memb;\n      } else {\n\tlast->next= memb;\n        last= memb;\n      }\n\n      // Stop if there is no next member\n      if (memb->next == NULL) return(0);\n    }\n  }\n\n  // For now set ctype to NULL\n  sym->ctype=NULL;\n\n  return(0);\n}\n\nvoid dumptable(struct symtable *head, int indent);\n\n// Dump a single symbol\nvoid dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n    case P_VOID:\n      printf(\"void \");\n      break;\n    case P_CHAR:\n      printf(\"char \");\n      break;\n    case P_INT:\n      printf(\"int \");\n      break;\n    case P_LONG:\n      printf(\"long \");\n      break;\n    case P_STRUCT:\n      printf(\"struct \");\n      break;\n    case P_UNION:\n      printf(\"union \");\n      break;\n    default:\n      printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++)\n    printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      break;\n    case S_FUNCTION:\n      printf(\"()\");\n      break;\n    case S_ARRAY:\n      printf(\"[]\");\n      break;\n    case S_STRUCT:\n      printf(\": struct\");\n      break;\n    case S_UNION:\n      printf(\": union\");\n      break;\n    case S_ENUMTYPE:\n      printf(\": enum\");\n      break;\n    case S_ENUMVAL:\n      printf(\": enumval\");\n      break;\n    case S_TYPEDEF:\n      printf(\": typedef\");\n      break;\n    case S_STRLIT:\n      printf(\": strlit\");\n      break;\n    default:\n      printf(\" unknown stype\");\n  }\n\n  printf(\" id %d\", sym->id);\n\n  switch (sym->class) {\n    case V_GLOBAL:\n      printf(\": global\");\n      break;\n    case V_LOCAL:\n      printf(\": local offset %d\", sym->st_posn);\n      break;\n    case V_PARAM:\n      printf(\": param offset %d\", sym->st_posn);\n      break;\n    case V_EXTERN:\n      printf(\": extern\");\n      break;\n    case V_STATIC:\n      printf(\": static\");\n      break;\n    case V_MEMBER:\n      printf(\": member\");\n      break;\n    default:\n      printf(\": unknown class\");\n  }\n\n  if (sym->st_hasaddr!=0)\n    printf(\", hasaddr \");\n\n  switch (sym->stype) {\n    case S_VARIABLE:\n      printf(\", size %d\", sym->size);\n      break;\n    case S_FUNCTION:\n      printf(\", %d params\", sym->nelems);\n      break;\n    case S_ARRAY:\n      printf(\", %d elems, size %d\", sym->nelems, sym->size);\n      break;\n  }\n\n  printf(\", ctypeid %d, nelems %d st_posn %d\\n\",\n\tsym->ctypeid, sym->nelems, sym->st_posn);\n\n  if (sym->initlist != NULL) {\n    printf(\"  initlist: \");\n    for (i=0; i< sym->nelems; i++)\n      printf(\"%d \", sym->initlist[i]);\n    printf(\"\\n\");\n  }\n\n  \n  if (sym->member != NULL)\n    dumptable(sym->member, 4);\n}\n\n// Dump one symbol table\nvoid dumptable(struct symtable *head, int indent) {\n  struct symtable *sym;\n\n  for (sym = head; sym != NULL; sym = sym->next)\n    dumpsym(sym, indent);\n}\n\nint main(int argc, char **argv) {\n  FILE *in;\n  struct symtable sym;\n\n  if (argc !=2) {\n    fprintf(stderr, \"Usage: %s symbolfile\\n\", argv[0]); exit(1);\n  }\n\n  in= fopen(argv[1], \"r\");\n  if (in==NULL) {\n    fprintf(stderr, \"Unable to open %s\\n\", argv[1]); exit(1);\n  }\n\n  while (1) {\n    if (deserialiseSym(&sym, in)== -1) break;\n    dumpsym(&sym, 0);\n  }\n  exit(0);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/detok.c",
    "content": "#include \"defs.h\"\n\n// C Lexical scanning: detokeniser\n// Copyright (c) 2023 Warren Toomey, GPL3\n\nchar Text[TEXTLEN + 1];\t\t// Last identifier scanned\nextern char *Tstring[];\n\n// Read at most count-1 characters from the\n// f FILE and store them in the s buffer.\n// Terminate the s buffer with a NUL.\n// Return NULL if unable to read or an EOF.\n// Else, return the original s pointer pointer.\nchar *fgetstr(char *s, size_t count, FILE * f) {\n  size_t i = count;\n  int ch;\n  char *ret = s;\n\n  while (i-- != 0) {\n    if ((ch = getc(f)) == EOF) {\n      if (s == ret)\n\treturn(NULL);\n      break;\n    }\n    *s++ = (char) ch;\n    if (ch == 0)\n      break;\n  }\n  *s = 0;\n  return(ferror(f) ? (char *) NULL : ret);\n}\n\nint main(int argc, char **argv) {\n  FILE *in;\n  int token;\n  int intval;\n\n  if (argc !=2) {\n    fprintf(stderr, \"Usage: %s tokenfile\\n\", argv[0]); exit(1);\n  }\n\n  in= fopen(argv[1], \"r\");\n  if (in==NULL) {\n    fprintf(stderr, \"Unable to open %s\\n\", argv[1]); exit(1);\n  }\n\n  // Read until no more tokens left\n  while (1) {\n    token = fgetc(in);\n    if (token == EOF)\n      break;\n\n    switch (token) {\n    case T_INTLIT:\n    case T_CHARLIT:\n      fread(&intval, sizeof(int), 1, in);\n      printf(\"%02X: %d\\n\", token, intval);\n      break;\n    case T_STRLIT:\n      fgetstr(Text, TEXTLEN + 1, in);\n      printf(\"%02X: \\\"%s\\\"\\n\", token, Text);\n      break;\n    case T_FILENAME:\n      fgetstr(Text, TEXTLEN + 1, in);\n      printf(\"%02X: filename \\\"%s\\\"\\n\", token, Text);\n      break;\n    case T_LINENUM:\n      fread(&intval, sizeof(int), 1, in);\n      printf(\"%02X: linenum %d\\n\", token, intval);\n      break;\n    case T_IDENT:\n      fgetstr(Text, TEXTLEN + 1, in);\n      printf(\"%02X: %s\\n\", token, Text);\n      break;\n    default:\n      printf(\"%02X: %s\\n\", token, Tstring[token]);\n    }\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "64_6809_Target/detree.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"misc.h\"\n#include \"tree.h\"\n\n// Deserialise an AST\n// Copyright (c) 2023 Warren Toomey, GPL3\n\nint showglue=0;\n\n// Generate and return a new label number\n// just for AST dumping purposes\nstatic int dumpid = 1;\nstatic int gendumplabel(void) {\n  return (dumpid++);\n}\n\n// List of AST node names\nstatic char *astname[] = { NULL,\n  \"ASSIGN\", \"ASPLUS\", \"ASMINUS\", \"ASSTAR\",\n  \"ASSLASH\", \"ASMOD\", \"TERNARY\", \"LOGOR\",\n  \"LOGAND\", \"OR\", \"XOR\", \"AND\", \"EQ\", \"NE\", \"LT\",\n  \"GT\", \"LE\", \"GE\", \"LSHIFT\", \"RSHIFT\",\n  \"ADD\", \"SUBTRACT\", \"MULTIPLY\", \"DIVIDE\", \"MOD\",\n  \"INTLIT\", \"STRLIT\", \"IDENT\", \"GLUE\",\n  \"IF\", \"WHILE\", \"FUNCTION\", \"WIDEN\", \"RETURN\",\n  \"FUNCCALL\", \"DEREF\", \"ADDR\", \"SCALE\",\n  \"PREINC\", \"PREDEC\", \"POSTINC\", \"POSTDEC\",\n  \"NEGATE\", \"INVERT\", \"LOGNOT\", \"TOBOOL\", \"BREAK\",\n  \"CONTINUE\", \"SWITCH\", \"CASE\", \"DEFAULT\", \"CAST\"\n};\n\n// Given an AST node, print it out and then\n// recursively deal with the sub-nodes.\nvoid dumpAST(struct ASTnode *n, int label, int level) {\n  int Lfalse, Lstart, Lend;\n  int i;\n  struct ASTnode *nleft=NULL, *nmid=NULL, *nright=NULL;\n\n  if (n == NULL)\n    fatal(\"NULL AST node\");\n  if (n->op > A_CAST)\n    fatald(\"Unknown dumpAST operator\", n->op);\n\n  // Load in the sub-nodes\n  if (n->leftid) nleft=loadASTnode(n->leftid,0);\n  if (n->midid) nmid=loadASTnode(n->midid,0);\n  if (n->rightid) nright=loadASTnode(n->rightid,0);\n\n  // Deal with IF and WHILE statements specifically\n  switch (n->op) {\n    case A_IF:\n      Lfalse = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"IF\");\n      if (nright) {\n\tLend = gendumplabel();\n\tfprintf(stdout, \", end L%d\", Lend);\n      }\n      fprintf(stdout, \" (id %d)\\n\", n->nodeid);\n      dumpAST(nleft, Lfalse, level + 2);\n      dumpAST(nmid, NOLABEL, level + 2);\n      if (nright)\n\tdumpAST(nright, NOLABEL, level + 2);\n      free(n);\n      return;\n    case A_WHILE:\n      Lstart = gendumplabel();\n      for (i = 0; i < level; i++)\n\tfprintf(stdout, \" \");\n      fprintf(stdout, \"WHILE start L%d (id %d)\\n\", Lstart, n->nodeid);\n      Lend = gendumplabel();\n      dumpAST(nleft, Lend, level + 2);\n      if (nright)\n\tdumpAST(nright, NOLABEL, level + 2);\n      free(n);\n      return;\n  }\n\n  // Reset level to -2 for A_GLUE nodes\n  if (n->op == A_GLUE) {\n    if (showglue) fprintf(stdout, \"glue %d %d\\n\", n->leftid, n->rightid);\n    level -= 2;\n  } else {\n\n    // General AST node handling\n    for (i = 0; i < level; i++)\n      fprintf(stdout, \" \");\n    fprintf(stdout, \"%s\", astname[n->op]);\n    if (n->symid != 0)\n      fprintf(stdout, \" symid %d\", n->symid);\n    switch (n->op) {\n      case A_FUNCTION:\n      case A_FUNCCALL:\n      case A_ADDR:\n      case A_PREINC:\n      case A_POSTINC:\n\tif (n->name != NULL)\n\t  fprintf(stdout, \" %s\", n->name);\n\tbreak;\n      case A_INTLIT:\n\tfprintf(stdout, \" %d\", n->a_intvalue);\n\tbreak;\n      case A_STRLIT:\n\tfprintf(stdout, \" rval \\\"%s\\\"\", n->name);\n\tbreak;\n      case A_IDENT:\n\tif (n->name != NULL) {\n\t  if (n->rvalue)\n\t    fprintf(stdout, \" rval %s\", n->name);\n\t  else\n\t    fprintf(stdout, \" %s\", n->name);\n\t}\n\tbreak;\n      case A_DEREF:\n\tif (n->rvalue)\n\t  fprintf(stdout, \" rval\");\n\tbreak;\n      case A_SCALE:\n\tfprintf(stdout, \" %d\", n->a_size);\n\tbreak;\n      case A_CASE:\n\tfprintf(stdout, \" %d\", n->a_intvalue);\n\tbreak;\n      case A_CAST:\n\tfprintf(stdout, \" %d\", n->type);\n\tbreak;\n    }\n    fprintf(stdout, \" (id %d)\\n\", n->nodeid);\n  }\n\n  // General AST node handling\n  if (nleft) dumpAST(nleft, NOLABEL, level + 2);\n  if (nmid) dumpAST(nmid, NOLABEL, level + 2);\n  if (nright) dumpAST(nright, NOLABEL, level + 2);\n  if (n->name!=NULL) free(n->name);\n  free(n);\n}\n\nint main(int argc, char **argv) {\n  struct ASTnode *node;\n  int fileid= 1;\n\n  if (argc !=2 && argc!=3) {\n    fprintf(stderr, \"Usage: %s [-g] astfile\\n\", argv[0]); exit(1);\n  }\n\n  if (!strcmp(argv[1], \"-g\")) {\n   showglue=1; fileid=2;\n  }\n\n  Infile= fopen(argv[fileid], \"r\");\n  if (Infile==NULL) {\n    fprintf(stderr, \"Unable to open %s\\n\", argv[fileid]); exit(1);\n  }\n\n  Idxfile= tmpfile();\n  mkASTidxfile();               // Build the AST index offset file\n\n  // Loop reading the next function's top node in from file\n  while (1) {\n    node= loadASTnode(0, 1);\n    if (node==NULL) break;\n\n    // Dump the function's tree\n    dumpAST(node, NOLABEL, 0);\n    printf(\"\\n\\n\");\n  }\n  return (0);\n}\n"
  },
  {
    "path": "64_6809_Target/docs/NOTES.md",
    "content": "## Thu 16 May 2024 10:41:14 AEST\n\nA start on cwj for the 6809. I'm using a simple approach:\nuse memory locations as the registers. Later on, I'll\nimprove the code quality.\n\nI also need to split the compiler into phases. One to\nparse and make the AST and the symbol table. The other\nto output the assembly from the AST and symbol table.\n\nHopefully I can get it all to fit into 64K!\n\nRight now I can do:\n\n```\nint p=3; int q=4;\nint main() { p= p + q; return(0); }\n```\n\n## Thu 16 May 2024 14:55:39 AEST\n\nI added the code to push arguments and fix up\nthe stack after a function call. I can call\n`printint()` which work. However, my compiler\nisn't adding the leading underscore. To fix.\n\n## Thu 16 May 2024 15:13:22 AEST\n\nFixed the `_` by adding it to all the `fprintf()`s\nin `cg.c`.\n\n## Thu 16 May 2024 16:49:54 AEST\n\nHmm. Small int lits are treated as char lits, but\nI need them to be int sized for `printf()`. \n\nAh. I already did this when I last tried to write\na 6809 compiler using `cwj`, see\ncloud/Nine_E/Old/Compiler` dated June 2023!\n\nI've imported some of that code which has helped.\n\n## Sat 18 May 2024 10:00:44 AEST\n\nOK I've finished the conversion of `cg.c` to 6809 but\nno testing yet. Just about to change over to the `crt0`\nwhich has stdio suuport, because all the tests use\nprintf. I'm using the `libc` compiled by `fcc` for now.\n\n## Sat 18 May 2024 13:44:47 AEST\n\nNot quite finished. I'd forgotten the comparisons.\nI've done them except for longs. Now up to\ninput009.c: OK.\n\n## Sat 18 May 2024 14:33:42 AEST\n\nNow up to input022.c: OK.\n\n## Sat 18 May 2024 15:11:34 AEST\n\nNow up to input054.c: OK\n\n## Sat 18 May 2024 15:24:25 AEST\n\nNow up to input114.c: OK\nWow!\n\n## Mon 20 May 2024 10:42:50 AEST\n\nTest 115 was a sizeof test which is now different on the 6809\ncf. amd64 :-) So now we are up to input135.c: OK.\n\nTest 136 is essentially this:\n\n```\nresult= 3 * add(2,3) - 5 * add(4,6);\n```\n\nI've checked the debug output and the `add()` is working fine.\nHowever, on the first `add()` return I see:\n\n```\n       lbsr _add\n        leas 4,s\n        puls d\n        std     R0\n        std     R1\n```\n\nwhich doesn't make sense as `R0` has the 3 from the `3*`.\nI see the problem. We push any in-use local registers on\nthe stack before a function call. On return, we pop them\noff and restore them. Then we save the function's return\nvalue.\n\nBut the function uses `Y,D` to hold the return value,\nand these are getting destroyed by the register popping.\n\nOK fixed with a slightly ugly fix. Now up to\ninput143.c OK.\n\n## Mon 20 May 2024 12:33:02 AEST\n\nYay. I now pass all the tests :-) I had to import some\nstuff from the Fuzix include files into my include files.\nThat means I can now start on breaking the compiler up\ninto phases.\n\nThere are going to be eight phases.\n\n1. The C pre-processor interprets #include, #ifdef\n   and the pre-processor macros.\n2. The lexer reads this and produces a token stream.\n3. The parser reads the token stream and creates\n   a symbol table plus a set of AST trees.\n4. The AST optimiser reads the trees and optimises them.\n5. The code generator reads the new AST trees and\n   the symbol table, and generates assembly code.\n6. The peephole optimiser improves the assembly code.\n7. The assembler produces object files.\n8. The linker takes crt0.o, the object files and\n   several libraries and produces an executable.\n\nAs well, there will be debug tools to:\n - dump the token stream,\n - dump the AST trees, and\n - dump the symbol table\n\nFor the symbol table, it will be in a file that\nhas the globals, prototypes, struct/union/typedef\ndefines. Then followed by sections that have the\nper-function symbols.\n\nThe AST file will have several separate AST trees,\none for each function.\n\nI already did some of this when I was working on\nPipeC, so I can borrow this code. Yay!\n\n## Mon 20 May 2024 14:55:17 AEST\n\nI've got separate scanner and detok programs with\nthe code borrowed from PipeC. I also added tokens\nthat hold the new filename and new linenumber when\nthese change. The weird thing is that, from this\ninput:\n\n```\n# 0 \"scan.c\"\n# 0 \"<built-in>\"\n# 0 \"<command-line>\"\n# 1 \"scan.c\"\n# 1 \"defs.h\" 1\n# 1 \"/tmp/include/stdlib.h\" 1 3 4\n\n\n\n\n# 4 \"/tmp/include/stdlib.h\" 3 4\nvoid exit(int status);\n...\n```\n\nI get these tokens:\n\n```\n1E: void\n43: filename \"/tmp/include/stdlib.h\"\n44: linenum 4\n36: exit\n39: (\n20: int\n36: status\n3A: )\n35: ;\n```\n\nwith the `void` coming before the filename!\nIt's because of the `scan()` recursion. I've\ngot it fixed now. The line numbers do seem to\nbe a bit out, though.\n\n## Tue 21 May 2024 09:57:34 AEST\n\nSo, I've rebuilt the compiler with a front-end which\nreads the token stream from stdin and calls\n`global_declarations()` to start the compilation. Right\nnow it outputs mostly the same assembly code, except for:\n\n```\ninput021.s has changed in the tree\ninput058.s has changed in the tree\ninput084.s has changed in the tree\ninput089.s has changed in the tree\ninput090.s has changed in the tree\ninput134.s has changed in the tree\ninput140.s has changed in the tree\ninput148.s has changed in the tree\n```\n\nSo now I've got some stuff to look at!\nAh, I'd forgotten the CHARLITs in the\ntoken decoder. Fixed. Now the compiler\nproduces the same assembly files for\nall tests. Yay!\n\n## Tue 21 May 2024 11:08:53 AEST\n\nI'm now working on the parsing phase.\nI've got the code now to serialise\nall the ASTs out to stdout and there is\na `detree` to print the trees.\n\nThere's a small problem that we used to\ngenerate assembly for string literals\nalong with labels while parsing. I've\ncommented this out for now but it will\nneed fixing.\n\nNow I need to dink `gen.c` out from\nthe parser, and also work out to\ndump the symbol table!\n\n## Tue 21 May 2024 11:24:39 AEST\n\nI've pulled `gen.c` and `cg.c` out\nfrom the parser. I had to abstract out\na few functions from these files into a\nnew `target.c` file which can be shared\nby the parser and code generator.\n\nNow to think about the symbol table serialisation.\n\nI'm worried that we might do:\n\n```\n<global variable>\n<function1>\n<global variable>\n<function2>\n```\n\nIf we dump out the global symbol table before\n`function1` then we won't have the second\nglobal variable.\n\nCan I just seralise symbols as they get declared?\nNo as they get modified e.g. an array with declared\nelements. Perhaps I keep pointers to the last symbols\ndumped, and dump from there each time we complete a\nfunction?\n\n## Tue 21 May 2024 16:53:06 AEST\n\nOK, I've got the start for the serialisation code.\nNow need to write the deserialiser and see where\nthe bugs are.\n\n## Wed 22 May 2024 08:28:42 AEST\n\nI rewrote the serialising code a bit. It runs and\ndoesn't crash. Now to write the deserialiser!\n\nOK, I've got a start so I can see what's in the symbol file.\nStill not right as yet.\n\nFound a couple of bugs and fixed them. Right now I'm only\ndumping the symbols, I'm not rebuilding the symbol table.\nThat will require a new program, the code generator. This\nwill do the symbol table and AST deserialising, and have:\n\n```\ngen.c misc.c sym.c tree.c type.c cg.c\n```\n\n## Wed 22 May 2024 15:26:54 AEST\n\nI now have a code generator and it's actually working. I\nhad to fix a bunch of things like storing string lits in\nthe AST so I could generate them later. But I'm now passing\nthe first dozen tests! Yay!\n\nWe are now up to input025.c: OK. Wow. Test 26 is failing\nbecause none of the params or locals have a frame offset.\n\n## Wed 22 May 2024 16:42:47 AEST\n\nActually they do, but I had a bug in my find symbol by id code.\nWe are now up to input057.c OK.\n\n## Thu 23 May 2024 10:17:43 AEST\n\nAh, I was serialising the globals first in the symbol table\nbut they may be of struct type, so I need to output the\nstructs, enums and unions before the globals. Now up to\ninput073.c: OK.\n\nThat was because I switched to the literal segment from the\ntext segment, and went to the data segment not back to the\ncode segment! Now up to input088.c: OK.\n\nSo the problem is:\n\n```\nchar *z= \"Hello world\";\n```\n\nIn the original code, we could generate the string literal, get\na label for it and then generate the global `z` with the label.\nNow the string gets lost and `z` is initialised to zero. We also\nhave to deal with `char *z=NULL;` also.\n\nI was thinking of putting the characters of the string in the\nsymbol's `initlist` and setting `nelems` to the string length,\nbut what if the initial value is NULL? Can I set `nelems` to\nzero? But what if we do `char *z= \"\";`, so not NULL but no\ncharacters? Hmm ... No that's not an answer.\n\nAnd we also need to support:\n\n```\nchar *fred[]= { \"Hello\", \"there\", \"Warren\", \"piano\", NULL };\n```\n\nwhich the original `cwj` compiler supported. Maybe I need another\nsymbol table for string literals. Then I can serialise that and\ngenerate the strings and labels in the back end?\n\n## Fri 24 May 2024 06:32:06 AEST\n\nMy solution will be the string literal symbol tables. The initlist\nfor `char *` globals will have the symid dumped in the symfile.\nIn the generator, we load the symbol tables. We generate the asm code\nfor the string literals & make a label. Then when we hit a `char *`\nglobal we replace the symids in the initlist with the relevant labels.\n\n## Fri 24 May 2024 09:42:04 AEST\n\nOK. Implemented. Seems to work. We are now up to input098.c: OK.\nActually, I forgot about arrays of strings. Now fixed and we are\nup to input129.c: OK.\n\nLooks like we are not dealing with this string literal as an\nexpression:\n\n```\n\"Hello \" \"world\" \"\\n\"\n```\n\n## Sat 25 May 2024 07:49:15 AEST\n\nAh yes, I wasn't incrementing `litlast` correctly in `primary()`,\nnow fixed. And now we pass all the tests! Some of the error reporting\nisn't exactly right, but that's fine. Yay, we have reached a milestone :-)\n\nI was thinking of bringing the QBE backend back in as well. Then we will\nhave two backends which might help reveal more bugs. Hopefully it won't\nbe too hard to adapt the existing backend to suit the rearranged compiler.\nAnd I also have to write the frontend which I'll call `wcc.c` to run\nall the phases correctly.\n\nSo here's a TODO list:\n\n - create the QBE backend, get it to work correctly\n - make it possible to build the compiler with each backend\n - change the final location to be `/opt/wcc` a la `fcc`\n - tease out the tree optimisation as an other phase, and\n   add some of the `SubC` optimisations\n - bring in the peephole optimiser from `fcc` and make it a phase\n - improve the 6809 code generation\n - add in `register, volatile, unsigned, float, double, const`\n - Eventually, start compiling the 6809 libc and see what other\n   language features I need to add.\n\nThis is going to take quite a while!\n\n## Sat 25 May 2024 08:30:19 AEST\n\nI've rearranged the filenames and massaged the Makefile so I now\nhave 6809-specific executables for \"parse\" and \"gen\". I imported\nthe QBE backend. The old compiler used to pass the type down into\nthe `cg` functions, whereas the new compiler doesn't do this. I\nthink I can go back to the old way, as it would help with other\nbackends apart from 6809 and QBE.\n\nOK, I've nearly everything. The new code pushes the function args\nwith one `cg` function and does the call with another. The existing\nQBE backend does it in one function. So I'll need to split that up.\nBut that's the only thing left to do, apart from testing it :-)\n\nActually the reason it changed for QBE is that QBE does the call\nfirst and the list of args second. I guess I could change the 6809\nversion to use this.\n\n## Sat 25 May 2024 17:14:01 AEST\n\nI've done the change and fixed a bug or two along the way. We \nare up to test input135.c: OK, so it's very close!\n\nAll tests now pass, I'd forgotten about spilling registers before\ncalling a function.\n\n## Sun 26 May 2024 08:09:25 AEST\n\nI'm working on `cgqbe.c` now. Almost done, I need to write `cgswitch()`\nin the QBE file; it was in `gen.c` in the QBE version previously.\n\n## Sun 26 May 2024 11:01:30 AEST\n\nI've written the `cgswitch()` in `cgqbe.c` and also added code to\ndelay outputting string literals until after the code. We are up to\ninput010.c: OK. A small issue, now up to input057.c: OK.\n\n## Sun 26 May 2024 11:42:03 AEST\n\nThe size of INTLITs used to access a struct member are longs in QBE,\nints on the 6809. Another target function added.\n\nWe are up to input062 which is the endianness test. I'll have to\nremove it for now. Now up to input074.c which is the first switch\ntest and which is failing at present.\n\n## Sun 26 May 2024 12:19:05 AEST\n\nI've fixed up the bug in `cgqbe.c` and also rearranged the switch\ngeneration code. Now all tests pass on both the 6809 and the QBE side.\nYay, I now have a compiler with two back ends!!!\n\n## Tue 28 May 2024 09:23:11 AEST\n\nI've written the front-end `wcc` and it now works for both QBE\nand 6809. I've moved install to `/opt/wcc`. I've rewritten\n`runtests` and `onetest`. Right now, for some reason, one of the\nQBE tests is failing. Sigh!\n\n## Tue 28 May 2024 10:34:14 AEST\n\nAh, there are several things in `include` which are different\nbetween 6809 and QBE. So we now have two `include` trees, one\nfor each platform. We now pass the tests again!\n\n## Tue 28 May 2024 11:12:20 AEST\n\nI just got the peephole optimiser added to the front-end. My\nfirst rule failed! Wonder why. Ah, I'd written the rule wrong, fixed.\nThe 6809 tests pass with the peephole optimiser working.\n\n## Tue 28 May 2024 11:50:54 AEST\n\nI teased out the AST optimiser as a standalone program, leaving it\nstill in the parser. It seems to work. However, I then tried to\nremove the optimiser from the parser with problems: We have this:\n\n```\ndecl.c:  // Parse the expression and optimise the resulting AST tree\ndecl.c:  tree = optimise(binexpr(0));\n```\n\nWith this line changed to `tree=binexpr(0);` instead, we die on\ntest 112 with `Cannot initialise globals with a general expression`. Why:\n\n```\nint x= 10 + 6;\n```\n\nThese need to be resolved at parse time. Argh! Perhaps I can keep\nsome of the tree optimisation code in the parser? Don't know.\n\nJust looking at the current amd64 binary sizes:\n\n```\n   text\t   data\t    bss\t    dec\t    hex\tfilename\n   9973\t   1008\t   4200\t  15181\t   3b4d\twcc\n   8902\t    676\t    680\t  10258\t   2812\tcscan\n  13695\t    752\t   1328\t  15775\t   3d9f\tcpeep\n  38772\t   1880\t    936\t  41588\t   a274\tcparse6809\n  47917\t   1456\t   1064\t  50437\t   c505\tcgen6809\n  38796\t   1880\t    936\t  41612\t   a28c\tcparseqbe\n  35088\t   1264\t    968\t  37320\t   91c8\tcgenqbe\n```\n\nIt looks like the 6809 generator needs some dieting before the parser does.\n\nI decided to try compiling the compiler code itself with the 6809 compiler:\n\n```\n$ for i in *.c; do wcc -c -m 6809 $i; done\nExpecting a primary expression, got token:void on line 27 of cgen.c\nType mismatch: literal vs. variable on line 20 of cgqbe.c\nUnrecognised character \\\nUnrecognised character \\\nUnrecognised character \\\nUnrecognised character \\\nUnrecognised character \\\nType mismatch: literal vs. variable on line 35 of cpeep.c\nExpecting a primary expression, got token:void on line 23 of ctreeopt.c\nExpecting a primary expression, got token:void on line 25 of desym.c\nUnrecognised character \\\nUnrecognised character \\\nExpecting a primary expression, got token:void on line 22 of detok.c\nExpecting a primary expression, got token:void on line 25 of detree.c\nExpecting a primary expression, got token:void on line 27 of parse.c\n& operator must be followed by an identifier on line 604 of scan.c\nUnrecognised character \\\nUnknown variable or function:s on line 143 of tree.c\nExpecting a primary expression, got token:} on line 17 of wcc.h\n\n$ ls *.o\n 71859 May 28 13:30 cg6809.o\n   688 May 28 13:26 crt0.o\n 33009 May 28 13:30 decl.o\n 29981 May 28 13:30 expr.o\n 22461 May 28 13:30 gen.o\n  1342 May 28 13:30 misc.o\n  3639 May 28 13:30 opt.o\n 12545 May 28 13:30 stmt.o\n 22795 May 28 13:30 sym.o\n  1053 May 28 13:30 targ6809.o\n  1393 May 28 13:30 targqbe.o\n   126 May 28 13:30 tstring.o\n  6732 May 28 13:30 types.o\n```\n\nInteresting. I need to find out why the scanner/parser is dieing.\nAlso `cg6809.o` is way too big!\n\n## Tue 28 May 2024 14:03:18 AEST\n\nI fixed the bug where the scanner could not deal with `\\\"` inside\nstring literals. We now have:\n\n```\nExpecting a primary expression, got token:void on line 27 of cgen.c\nType mismatch: literal vs. variable on line 20 of cgqbe.c\nType mismatch: literal vs. variable on line 35 of cpeep.c\nExpecting a primary expression, got token:void on line 23 of ctreeopt.c\nExpecting a primary expression, got token:void on line 25 of desym.c\nExpecting a primary expression, got token:void on line 22 of detok.c\nExpecting a primary expression, got token:void on line 25 of detree.c\nExpecting a primary expression, got token:void on line 27 of parse.c\n& operator must be followed by an identifier on line 612 of scan.c\nExpecting a primary expression, got token:} on line 17 of wcc.h\n```\n\nThe problem is that the line numbers are a bit bogus :-(\n\nAh, the bug is that my compiler doesn't allow `return <expression>;`,\nit only likes `return(<expression>);`.\n\n## Tue 28 May 2024 14:26:43 AEST\n\nI tried to fix it but it's hard. We have to be able to deal with:\n\n```\n    return( (void *)0 );\nand\n    return (void *)0 ;\n```\n\nFor now I'll just fix my own code. Done.\n\n## Tue 28 May 2024 14:47:59 AEST\n\nThe `& operator must be followed by an identifier` is because we\ncan't do this yet:\n\n```\nmary= &fred.x;\n```\n\nOK, down to these:\n\n```\n$ for i in *.c; do wcc -S -m6809 $i; done\nType mismatch: literal vs. variable on line 20 of cgqbe.c\nType mismatch: literal vs. variable on line 35 of cpeep.c\n```\n\n## Tue 28 May 2024 15:14:56 AEST\n\nI'm down to one source file now:\n\n```\n$ for i in *.c; do wcc -c -m6809 $i; done\nIncompatible types in binary expression on line 95 of cpeep.c\n\n$ ls *.o\n 71859 May 28 15:14 cg6809.o\n 12497 May 28 15:14 cgen.o\n 37028 May 28 15:14 cgqbe.o\n   688 May 28 15:13 crt0.o\n  8427 May 28 15:14 ctreeopt.o\n 33009 May 28 15:14 decl.o\n  4832 May 28 15:14 desym.o\n  3093 May 28 15:14 detok.o\n  3336 May 28 15:14 detree.o\n 29981 May 28 15:14 expr.o\n 22461 May 28 15:14 gen.o\n  1342 May 28 15:14 misc.o\n  3639 May 28 15:14 opt.o\n  8853 May 28 15:14 parse.o\n 23115 May 28 15:14 scan.o\n 12545 May 28 15:14 stmt.o\n 22795 May 28 15:14 sym.o\n  1053 May 28 15:14 targ6809.o\n  1393 May 28 15:14 targqbe.o\n  9685 May 28 15:14 tree.o\n   126 May 28 15:14 tstring.o\n  6732 May 28 15:14 types.o\n 19125 May 28 15:14 wcc.o\n```\n\nI decided to get `fcc` to compile the code. The results are:\n\n```\n$ ls *.o\n 35320 May 28 15:21 cg6809.o\n  5587 May 28 15:21 cgen.o\n 16838 May 28 15:21 cgqbe.o\n 17642 May 28 15:21 cpeep.o\n  3965 May 28 15:21 ctreeopt.o\n 14467 May 28 15:21 decl.o\n  2308 May 28 15:21 desym.o\n  1569 May 28 15:21 detok.o\n  1520 May 28 15:21 detree.o\n 11534 May 28 15:21 expr.o\n  8617 May 28 15:21 gen.o\n   742 May 28 15:21 misc.o\n  1521 May 28 15:21 opt.o\n  4228 May 28 15:21 parse.o\n 11414 May 28 15:21 scan.o\n  5617 May 28 15:21 stmt.o\n 10648 May 28 15:21 sym.o\n   761 May 28 15:21 targ6809.o\n   903 May 28 15:21 targqbe.o\n  5152 May 28 15:21 tree.o\n  2012 May 28 15:21 tstring.o\n  2515 May 28 15:21 types.o\n 10225 May 28 15:21 wcc.o\n```\n\nor about half the size :-)\n\nOK, just for fun I built `cgen6809` using the `fcc` compiler.\nI get `8A91 B __end` as the size. And for `cparse6809` we have\n`765A B __end` :-)\n\nAnd the amd64 versions have these size:\n\n```\n$ size cparse6809 cgen6809\n   text\t   data\t    bss\t    dec\t    hex\tfilename\n  38793\t   1880\t    936\t  41609\t   a289\tcparse6809\n  47942\t   1456\t   1064\t  50462\t   c51e\tcgen6809\n```\n\nSo, if we can get the code generator to be around as good as `fcc`\nthen we stand a chance of getting it to cross-compile. Lots of\nwork to do.\n\n## Tue 28 May 2024 16:34:46 AEST\n\nJust brainstorming the code improvement. We sort of have to keep\nthe register idea in `gen.c` so as to support QBE. How about:\n\n - cg6809.c keeps an array of Location structs\n - the index into the array is a \"register\"\n - global `d_free` so we know when we can load the D register\n - the Location holds enough details to use as an operand\n   to the B/D/Y operations.\n\nLooking at the current code:\n\n```\nldd #0\\n\");\nldd 0,x\\n\");\nldd #1\\n\");\nldd 2,x\\n\");\nldd #%d\\n\", offset);\nldd #%d\\n\", offset & 0xffff);\nldd #%d\\n\", val & 0xff);\nldd #%d\\n\", value & 0xffff);\nldd #%d\\n\", (value>>16) & 0xffff);\nldd %d,u\\n\", 2+sym->st_posn);\nldd %d,u\\n\", sym->st_posn);\nldd #L%d\\n\", label);\nldd _%s+2\\n\", sym->name);\nldd #_%s\\n\", sym->name);\nldd _%s\\n\", sym->name);\n```\n\nso we need to record:\n\n - symbol names with optional position\n - offset on the stack frame\n - constants\n - label-ids\n - address of symbol names\n\nSomething like:\n\n```\nenum {\n  L_SYMBOL,\n  L_LOCAL,\n  L_CONST,\n  L_LABEL,\n  L_SYMADDR,\n  L_DREG\n};\n\nstruct Location {\n  int type;\n  char *name;\n  int intval;\t\t// Offset, const value, label-id\n};\n```\nand a function which prints out the Location. We keep the\nregister allocation/freeing and we can set `d_free` true\nwhen we free all registers. Register spilling should be\nsimpler. The `cg` functions which allocate a register\nwill now allocate a Location element and fill it in.\n\nThen, something like:\n\n```\nint cgadd(int r1, int r2, int type) {\n  int size= cgprimsize(type);\n\n  // If r1 is already L_DREG, do nothing.\n  // Otherwise load the existing r1 location\n  // into D and mark it as L_DREG.\n  // This could load B, D or Y,D\n  load_d(r1, size);\t\n\n  switch (size) {\n    case 1: fprintf(Outfile, \"\\taddb\"); printlocation(r2,0); break;\n    case 2: fprintf(Outfile, \"\\taddd\"); printlocation(r2,0); break;\n    case 4: fprintf(Outfile, \"\\taddd\"); printlocation(r2,2);\n\t    // Some code here to update Y :-)\n  }\n  return(r1);\n}\n```\n\n## Wed 29 May 2024 09:01:58 AEST\n\nI got a start last night with good results. I've thought of some\nimprovements and will try to get some done now.\n\nI can compile this so far:\n\n```\nint x, y, z;\n\nint main() {\n  int result; x=2; y=3; z=4;\n  result= x + y + z; printf(\"%d\\n\", result); return(result);\n}\n```\n\nwith the assembly (some bits omitted):\n\n```\n_main:\n\tpshs u\n\ttfr s,u\n\tleas -2,s\n\tldd #2\n\tstd _x\n\tldd #3\n\tstd _y\n\tldd #4\n\tstd _z\n\tldd _x+0\n\taddd _y+0\n\taddd _z+0\n\tstd -2,u\n\n\tldd -2,u\t; This could be improved!\n\tpshs d\n\tldd #L2\n\tpshs d\n\tlbsr _printf\n\tleas 4,s\n\n\tldd -2,u\n\tleas 2,s\n\tpuls u\n\trts\n```\n\nwhich is much nicer than going through R0, R1 etc.\n\n## Wed 29 May 2024 12:48:15 AEST\n\nIt's slow going. We are up to input009.c: OK though.\nNow input010.c: OK.\n\nI can see that dealing with longs isn't going to be fun.\n\n## Thu 30 May 2024 12:51:23 AEST\n\nFait went away with Liz today :-(\nWe are up to input026.c: OK\n\n## Thu 30 May 2024 13:19:48 AEST\n\nNow up to input090.c OK.\n\n## Thu 30 May 2024 14:05:55 AEST\n\nNow up to input139.c: OK\n\n## Thu 30 May 2024 15:09:40 AEST\n\nYay, all the tests now pass. Wow.\n\nFor a lark I tried to compile the compiler source with itself:\n\n```\n$ for i in *.c; do wcc -c -m6809 $i; done\nIncompatible argument type in function call on line 58 of cg6809.c\nOut of locations in cgalloclocn on line 241 of (null)\nIncompatible types in binary expression on line 95 of cpeep.c\nOut of locations in cgalloclocn on line 284 of (null)\nOut of locations in cgalloclocn on line 41 of (null)\nchild phase didn't Exit\nOut of locations in cgalloclocn on line 69 of (null)\nchild phase didn't Exit\nOut of locations in cgalloclocn on line 48 of (null)\n```\n\nSo a few files didn't compile, but for those here are\nthe size changes from the old to new code generator:\n\n```\nOld Size              New Size\t\tFcc Size\n------------------------------------------------\n 71859 cg6809.o\n 12497 cgen.o\t\t7890\t\t5587\n 37028 cgqbe.o\n   688 crt0.o\n  8427 ctreeopt.o\t5530\t\t3965\n 33009 decl.o\n  4832 desym.o\t\t3464\t\t2308\n  3093 detok.o\t\t2242\t\t1569\n  3336 detree.o\t\t2313\t\t1520\n 29981 expr.o\n 22461 gen.o\t\t11608\t\t8617\n  1342 misc.o\t\t834\t\t742\n  3639 opt.o\t\t2132\t\t1521\n  8853 parse.o\t\t5897\t\t4228\n 23115 scan.o\n 12545 stmt.o\n 22795 sym.o\n  1053 targ6809.o\t806\t\t761\n  1393 targqbe.o\t1062\t\t903\n  9685 tree.o\n   126 tstring.o\t126\t\t2012\n  6732 types.o\t\t4385\t\t2515\n 19125 wcc.o\t\t13238\t\t10225\n```\n\nQuite an improvement I think. And there's more work to do as `fcc`\nis still much better.\n\n## Thu 30 May 2024 17:43:35 AEST\n\nFound a bug in `gen.c` because pointers and ints are different\nsizes in QBE/amd64. This line `Locn[l].type = 23;` failed because\n`l` was being multiplied by the struct size (as an int) but then\nwas added to the address of `Locn` (long vs. word). Fixed.\n\nNo, not fixed. It trips up later when it tries to widen a long\nto be a long, which QBE can't do (for some reason :-).\n\n## Thu 30 May 2024 20:02:32 AEST\n\nFixed and fixed a few others. We now have:\n\n```\n$ for i in *.c; do wcc -c $i; done\nIncompatible types in binary expression on line 95 of cpeep.c\nqbe:decl.c_qbe:2530: invalid type for first operand %class in copy\n```\n\nThe `cpeep.c` one is subtracting pointers and assigning to an int:\n\n```\nint main() {\n  char *a, *b;\n  int x;\n  x= a - b;\n  return(x);\n}\n```\n\nThe other one seems to be that `class` should be marked as having\nan address but it isn't. Not sure why not.\n\n## Fri 31 May 2024 08:56:58 AEST\n\nIdeas for putting the compiler on a diet.\n\n - More AST optimisations, e.g. add/sub/mul where one side is int lit 0.\n   But use an #ifdef to keep the gen ones away from the parse ones.\n   Also e.g. switch left/right on commutative ops so that D reg already\n   holds one of the values.\n - Use free() where possible\n - When an AST op is the top of the tree, don't load the D register with\n   the result, e.g. `i++;`.\n - Don't use variables, e.g. `int primtype= ...; switch(primtype)`\n - What ints can be turned into chars?\n - We need to keep P_POINTER even though it's the same as P_INT at\n   present. When we have `unsigned` then pointers will be unsigned,\n   but ints might be signed.\n - Find duplicated string lits and make them globals, so only declared once.\n - Definitely some 6809 code improvements.\n - More peephole optimisations\n - Do a code coverage analysis?\n - Move the temporaries on the stack. Use an assembler constant to `leas`\n   the stack at the start/end of each function. This will save us the\n   necessity of spilling temps on the stack.\n\n## Fri 31 May 2024 09:22:30 AEST\n\nSo we need to be able to add/subtract pointers. But we have to unscale\nthe result. Example (on amd64 gcc):\n\n```\n#include <stdio.h>\nint main() {\n  int a, b; int *x, *y; long z;\n  a=2; b=3; x=&a; y=&b;\n  printf(\"x is %lx y is %lx\\n\", x, y);\n  z= x - y;     printf(\"z is %lx\\n\", z);\n  z= x - y + 1; printf(\"z is %lx\\n\", z);\n  return(0);\n}\n```\n\nproduces\n\n```\nx is 7ffc7b25b244 y is 7ffc7b25b240\nz is 1\nz is 2\n```\n\nNote x and y are four bytes apart, but the subtraction gives 1 as a result.\nBut then the `+1` is treated as a long addition. Hmm.\n\nYes I think we will need an A_DESCALE AST operation and a `cgshrconst()`\nfunction.\n\n## Fri 31 May 2024 14:43:58 AEST\n\nLooking at the QBE `%class` problem in `decl.c`. I've got a new file `d.c`\nwith just the problem function `declaration_list()` in it. This compiles\nwith no problem! I even put in a function prototype just like in `decl.c`\nwith no problems. Hmm.\n\nIn the `sym` file, this is `class`:\n\n```\n{name = 0x555555566860 \"class\", id = 575, type = 48, ctype = 0x0, \n  ctypeid = 0, stype = 0, class = 3, size = 4, nelems = 1, st_hasaddr = 0, \n  st_posn = 0, initlist = 0x0, next = 0x555555566880, member = 0x0}\n```\n\nand `st_hasaddr` is zero. But I ran the parser through `gdb` and saw\nit being set to 1. So not sure how it got reset to 0.\n\nI ran the parser again. No, nothing is resetting it to 0. I modified\n`desym` to show `hasaddr` and none of the parameters have it set to 1.\n\nI added a printf to the parser and I see:\n\n```\nIn declaration_list set hasaddr 1 on class stype 0 class 3\n```\n\nwhich is a variable (0) parameter (3). Hmm. So why isn't it being\ndumped properly?\n\n## Sat 01 Jun 2024 10:03:16 AEST\n\nOK I think I can see the problem. The symbol is being dumped before\n`hasaddr` is set:\n\n```\n$ wcc -S -X -v decl.c\n...\nSerialising class stype 0 class 3 id 575 hasaddr 0\n...\nIn declaration_list set hasaddr 1 on class stype 0 class 3 id 575\n```\n\nI'm guessing that we serialise the `class` mentioned in the prototype\nwhen it has `hasaddr 0`. Later on, `hasaddr` gets set but as the\nsymbol was already serialised, the change doesn't make it out. Damn.\n\nWe have to output protptypes in the symbol table in case a function\ncalls a function which is only represented by the prototype.\n\nMy solution for now is to mark all parameters as having an address\nin `cgqbe.c`. I only have to do the parameters as they appear in\nthe prototypes. Sigh. All the tests still pass. Now we are down to:\n\n```\nIncompatible types in binary expression on line 95 of cpeep.c\n```\n\nBut as I don't use this in the QBE version of the compiler, I should\nbe able to try and compile the QBE compiler with itself.\n\n## Sat 01 Jun 2024 13:26:27 AEST\n\nThe `wcc` front-end doesn't work but I suspect system calls. `cscan`\nworks fine.\n\nDamn, the parser isn't right, I'm seeing:\n\n```\n$ ls *ast ; ls *sym\n 235105 Jun  1 13:28 decl.c_ast\n 216017 Jun  1 13:28 fred_ast\n 59119 Jun  1 13:28 decl.c_sym\n 56399 Jun  1 13:28 fred_sym\n```\n\nas the outputs, the \"fred\" ones are from `cparseqbe` compiled with `wcc`.\n\nAh, it looks like the struct sizes are different. I've run `detree`\n(compiled with wcc and gcc) and I see these differences:\n\n```\n<       STRLIT rval \\\"Can't have static/extern in a typedef declaration\\\"\n---\n>       STRLIT rval \"Can't have static/extern in a typedef declaration\"\n1641c1641\n<       STRLIT rval \\\"redefinition of typedef\\\"\n---\n>       STRLIT rval \"redefinition of typedef\"\n1669c1669\n<       STRLIT rval \\\"unknown type\\\"\n---\n>       STRLIT rval \"unknown type\"\n...\n```\n\nNot sure if that's bad or not. For the dumped symbol table, `desymqbe`\nproduces the same output except the `wcc` compiled one does a segfault\nright at the end. Sigh.\n\nDamn, I made the `.s` files for `desymqbe` and did a\n`cc -o desymqbe -g -Wall *.s` but that didn't tell me where it crashed.\n\nHmm, well I can actually do this:\n\n```\n$ ./wscan < decl.c_cpp > fred.tok\n$ ./wparseqbe fred_sym fred_ast < fred.tok\n$ ./wgenqbe fred_sym fred_ast > fred_qbe\n```\n\nwith no crashes. Doing a diff:\n\n```\n$ paste fred_qbe decl.c_qbe\n\n@L2     \t\t  @L2\n  %ctype =l alloc8 1      %ctype =l alloc8 1\n  storel %.pctype, %ctype storel %.pctype, %ctype\n  %class =l alloc8 1      %class =l alloc8 1\n  storel %.pclass, %class storel %.pclass, %class\n  %.t1 =w copy 0          %.t1 =w copy 0\n  %type =w copy %.t1      %type =w copy %.t1\n  %.t2 =w copy 1          %.t2 =w copy 1\n  %exstatic =w copy %.t2  %exstatic =w copy %.t2\n  %.t3 =w copy 0          %.t3 =w copy 0\n  %.t5 =l extsw %.t3      %.t5 =l extsw %.t3\n  %.t6 =l loadl $ctype    %.t6 =l loadl %ctype\t<===\n  storel %.t5, %.t6       storel %.t5, %.t6\n```\n\n`ctype` is a local and should always be `%ctype`,\nbut our compiler is producing `$ctype` which is\na global. Hmm ...\n\n## Sat 01 Jun 2024 15:23:22 AEST\n\nGoing back to `desymqbe`, I added a few printfs ...\n\n```\nint main() {\n  struct symtable sym;\n\n  while (1) {\nprintf(\"A\\n\");\n    if (deserialiseSym(&sym, stdin)== -1) break;\nprintf(\"B\\n\");\n    dumpsym(&sym, 0);\nprintf(\"C\\n\");\n  }\nprintf(\"D\\n\");\n  return(0);\n}\n```\n\nand when I run the version compiled with our compiler:\n\n```\nC\nA\nD\nSegmentation fault\n```\n\nSo it's segfaulting on the `return(0)`? When I change it\nto an `exit(0)` it's fine?! I'll do that for now.\n\n## Sat 01 Jun 2024 15:29:20 AEST\n\nSummary: we can link and run the passes but not the front-end `wcc`.\nDoing a compile of `decl.c` to assembly:\n\n- the token files are identical\n- the dumped symbol files are identical from the `desym` perspective\n- the strlits in the AST file are different. The self-compiled version\n  is putting \\ before each \"\n- the `cgenqbe` seems to be treating locals as globals here and there.\n\n## Sun 02 Jun 2024 09:42:19 AEST\n\nI moved the symbol dumping code from `sym.c` to `desym.c` and\nadded more code to print out everything.\n\nI need a name for the two sets of binaries. The G binaries are compiled\nwith `gcc`, the W binaries with `wcc`.\n\nThe G & W tokeniser produce the same token stream.\nThe G & W parser produce different symbol table files,\nbut when I run the G & W `desym` on them I get identical results.\n\nWe still have the STRLIT issue with the G & W `detree` outputs.\nThe AST files are different, but doing a `hd` on them I see:\n\n```\nG version\n00030440  00 00 00 00 44 75 70 6c  69 63 61 74 65 20 73 74  |....Duplicate st|\n00030450  72 75 63 74 2f 75 6e 69  6f 6e 20 6d 65 6d 62 65  |ruct/union membe|\n00030460  72 20 64 65 63 6c 61 72  61 74 69 6f 6e 00 1c 00  |r declaration...|\n\nW version\n00034880  00 00 00 00 44 75 70 6c  69 63 61 74 65 20 73 74  |....Duplicate st|\n00034890  72 75 63 74 2f 75 6e 69  6f 6e 20 6d 65 6d 62 65  |ruct/union membe|\n000348a0  72 20 64 65 63 6c 61 72  61 74 69 6f 6e 00 1c 00  |r declaration...|\n```\n\nso the literals are the same. It's just `detree` somehow printing out\nthem differently.\n\n## Sun 02 Jun 2024 10:03:32 AEST\n\nHmm. So I added code in `cgqbe.c` to print out how we decide to use\neither a local `%` or global `$` character. Yes, we get a wrong answer:\n\n```\n< loadvar ctype 3 -> %\n< loadvar exstatic 2 -> %\n---\n> loadvar ctype 3 -> $\n> loadvar exstatic 2 -> $\n\n< loadvar class 3 -> %\n< loadvar class 3 -> %\n---\n> loadvar class 3 -> $\n> loadvar class 3 -> $\n```\n\nThe code for this is:\n\n```\n  // Get the relevant QBE prefix for the symbol\n  qbeprefix = ((sym->class == C_GLOBAL) || (sym->class == C_STATIC) ||\n               (sym->class == C_EXTERN)) ? (char)'$' : (char)'%';\n```\n\nSo it might be LOGOR or ternaries or a combination of both?!\nI've got a test program and, for all class values we always get '$'\nand not '%'. Hmm.\n\nI'm comparing the QBE output from the `acwj 63` compiler. The LOGOR\ncode is the same. The ternary code isn't.\n\n## Mon 03 Jun 2024 13:47:00 AEST\n\nSo it turns out I hadn't thought through the cases where a) I need\na boolean value from an arbitrary expression and b) when to compare\nand jump, or) jump on a boolean value. The answer was as follows ...\n\nWe already have code in IF and WHILE statements, e.g.\n\n```\n  // Parse the following expression \n  // and the ')' following. Force a \n  // non-comparison operation to be boolean.\n  condAST = binexpr(0);\n  if (condAST->op < A_EQ || condAST->op > A_GE)\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n```\n\nAnd in `gen.c` and `cg.c`:\n\n```\n  case A_TOBOOL:\n    // If the parent AST node is an A_IF or A_WHILE, generate\n    // a compare followed by a jump. Otherwise, set the register\n    // to 0 or 1 based on it's zeroeness or non-zeroeness\n    return (cgboolean(leftreg, parentASTop, iflabel, type));\n...\n  case A_EQ:\n  case A_NE:\n  case A_LT:\n  case A_GT:\n  case A_LE:\n  case A_GE:\n    // If the parent AST node is an A_IF, A_WHILE or A_TERNARY,\n    // generate a compare followed by a jump. Otherwise, compare\n    // registers and set one to 1 or 0 based on the comparison.\n    if (parentASTop == A_IF || parentASTop == A_WHILE ||\n        parentASTop == A_TERNARY)\n      return (cgcompare_and_jump\n              (n->op, leftreg, rightreg, iflabel, n->left->type));\n    else\n      return (cgcompare_and_set(n->op, leftreg, rightreg, n->left->type));\n```\n\nSo, we can fix the problem by a) adding `mkastunary(A_TOBOOL...` to\nthe ternary expression code, and b) adding `parentASTop == A_TERNARY`\nto the `case A_TOBOOL`. I've just done this and now all the tests pass\nincluding a few extras I made up. Phew!\n\n## Mon 03 Jun 2024 14:00:23 AEST\n\nNow, going back to compiling `decl.c` with our own compiler, I now get:\n\n```\n$ md5sum decl.c_qbe fred.qbe\n0f299257e088b3de96b68430e9d1f123  decl.c_qbe\tG version\n0f299257e088b3de96b68430e9d1f123  fred.qbe\tW version\n```\n\n## Mon 03 Jun 2024 14:24:00 AEST\n\nWith a shell script that uses the W binaries to compile the passes down\nto QBE code, I think I should be able to pass the triple test!\n\n```\n18fe9843b22b0ad06acfbc2011864619  cg6809.c_qbe\tG version\n18fe9843b22b0ad06acfbc2011864619  fred.qbe\tW version\n===\nf7db53fe1cb35bd6ed19e633a5c618a6  cgen.c_qbe\nf7db53fe1cb35bd6ed19e633a5c618a6  fred.qbe\n===\n9bfc78b1ef9b08eecf9dde1046bc4ab6  cgqbe.c_qbe\n9bfc78b1ef9b08eecf9dde1046bc4ab6  fred.qbe\n===\n===\n76ec1c53e8362a69ef1935a5efd7a1e3  ctreeopt.c_qbe\n76ec1c53e8362a69ef1935a5efd7a1e3  fred.qbe\n===\n0f299257e088b3de96b68430e9d1f123  decl.c_qbe\n0f299257e088b3de96b68430e9d1f123  fred.qbe\n===\n62d30bbd1b3efc61a021fffe76fff670  desym.c_qbe\n62d30bbd1b3efc61a021fffe76fff670  fred.qbe\n===\n28e5d1e283ee25a6b7e08f1d69816de8  detok.c_qbe\n28e5d1e283ee25a6b7e08f1d69816de8  fred.qbe\n===\nc1cdef1a287717a429281f6c439475d4  detree.c_qbe\nc1cdef1a287717a429281f6c439475d4  fred.qbe\n===\n4c72e8a009e3e6730969b7d55a30b9b4  expr.c_qbe\n4c72e8a009e3e6730969b7d55a30b9b4  fred.qbe\n===\nea63b78d3fa59c8d540639d83df8cf75  gen.c_qbe\nea63b78d3fa59c8d540639d83df8cf75  fred.qbe\n===\nccb643e15e8cc51969ee41aac2a691e7  misc.c_qbe\nccb643e15e8cc51969ee41aac2a691e7  fred.qbe\n===\n58fd815735a4ff3586a460884e58e700  opt.c_qbe\n58fd815735a4ff3586a460884e58e700  fred.qbe\n===\n784b5c65469c655868761f5c4501739c  parse.c_qbe\n784b5c65469c655868761f5c4501739c  fred.qbe\n===\n453d1ccb4e334b9e2852fac87a87bcff  scan.c_qbe\n453d1ccb4e334b9e2852fac87a87bcff  fred.qbe\n===\n8d66ab6b83506b92ab7e747c9d645fa3  stmt.c_qbe\n8d66ab6b83506b92ab7e747c9d645fa3  fred.qbe\n===\nd91591705e6e99733269781f4f44bf47  sym.c_qbe\nd91591705e6e99733269781f4f44bf47  fred.qbe\n===\n30e39b30644aead98e47ccd5ebf6171c  targ6809.c_qbe\n30e39b30644aead98e47ccd5ebf6171c  fred.qbe\n===\n0be7b46eb6add099be91cd3721ec4f09  targqbe.c_qbe\n0be7b46eb6add099be91cd3721ec4f09  fred.qbe\n===\n73bd8faa39878c98f40397e0cf103408  tree.c_qbe\n73bd8faa39878c98f40397e0cf103408  fred.qbe\n===\n7cf6e7e9ad7f587e31e3163aad1a40f3  tstring.c_qbe\n7cf6e7e9ad7f587e31e3163aad1a40f3  fred.qbe\n===\n392531419455d54d333922f37570cb61  types.c_qbe\n392531419455d54d333922f37570cb61  fred.qbe\n===\nd7a3ddeafccf98d03d2fe594e78f2689  wcc.c_qbe\nd7a3ddeafccf98d03d2fe594e78f2689  fred.qbe\n```\n\nAll the checksums are identical.\n\n## Tue 04 Jun 2024 08:53:19 AEST\n\nI rearranged the `Makefile` so that it is set up to run the triple test\nwith the QBE back-end. The level 0 binaries are built with `gcc`. The\nlevel 1 binaries in `L1/` are built with the level 0 binaries. The\nlevel 2 binaries in `L2/` will get built with the level 1 binaries.\nThus, the files in `L1/` and `L2` should be identical except for `wcc`\nas BINDIR is different.\n\nThere's still a problem with `wcc`. I can do:\n\n```\n$ L1/wcc -S  wcc.c      and\n$ L1/wcc -c  wcc.c\n```\n\nBut when I try to do the link stage it just loops around doing:\n\n```\n$ L1/wcc -o wcc -v  wcc.c\nDoing: cpp -nostdinc -isystem /usr/local/src/Cwj6809/include/qbe wcc.c \n  redirecting stdout to wcc.c_cpp\nDoing: /usr/local/src/Cwj6809/L1/cscan \n  redirecting stdin from wcc.c_cpp\n  redirecting stdout to wcc.c_tok\nDoing: /usr/local/src/Cwj6809/L1/cparseqbe wcc.c_sym wcc.c_ast \n  redirecting stdin from wcc.c_tok\nDoing: /usr/local/src/Cwj6809/L1/cgenqbe wcc.c_sym wcc.c_ast \n  redirecting stdout to wcc.c_qbe\nDoing: qbe -o wcc.c_s wcc.c_qbe \nDoing: as -o wcc.c_o wcc.c_s \nDoing: cpp -nostdinc -isystem /usr/local/src/Cwj6809/include/qbe wcc.c \n  redirecting stdout to wcc.c_cpp\nDoing: /usr/local/src/Cwj6809/L1/cscan \n  redirecting stdin from wcc.c_cpp\n  redirecting stdout to wcc.c_tok\n...\n```\n\nI have found the problem. Here's the test code:\n\n```\n#include <stdio.h>\nint i;\nint main() {\n  for (i=1; i<= 10; i++) {\n    if (i==4) { printf(\"I don't like 4 very much\\n\"); continue; }\n    printf(\"i is %d\\n\", i);\n  }\n  return(0);\n}\n```\n\nThe `continue` should take us to the code that does the `i++`\nbefore we do the `i<=10` test. But the compiler is taking\nus to the `i<=10` test and we get stuck in an infinite loop\nwith `i` set to 4. Sigh.\n\nI'm not sure how to deal with this. When I parse a `for` loop\nI simply glue the postop tree to the end of the loop body\nand treat it as a `while` loop. So there's only the label\nbefore the condition test and the label at the loop's end.\nThere's no label between the body and the postop code.\n\nFor now I can rewrite `wcc` to avoid the problem. And, yes,\nwe now pass the triple test:\n\n```\nmd5sum L1/* L2/* | sort\n424d006522f88a6c8750888380c48dbe  L1/desym\n424d006522f88a6c8750888380c48dbe  L2/desym\n5da0fd17d14f35f19d1e1001c4ffa032  L2/wcc\n6459d5698068115890478e4498bad693  L1/wcc\n74ce22e789250c3c406980dab1c37df1  L1/detok\n74ce22e789250c3c406980dab1c37df1  L2/detok\n9cd8c07f0b66df2c775cfa348dfac4f7  L1/cscan\n9cd8c07f0b66df2c775cfa348dfac4f7  L2/cscan\n9fbe13d2b8120797ace55a37045f2a48  L1/cgenqbe\n9fbe13d2b8120797ace55a37045f2a48  L2/cgenqbe\na9f109370f44ce15b9245d01b7b03597  L1/cparseqbe\na9f109370f44ce15b9245d01b7b03597  L2/cparseqbe\nebed2d69321e600bc3f5a634eb1ac1f8  L1/detree\nebed2d69321e600bc3f5a634eb1ac1f8  L2/detree\n```\n\nYayy!!! I just merged the `bettercode` branch back in\nto the `master` branch.\n\n## Tue 04 Jun 2024 10:12:29 AEST\n\nBack to the 6809 side now that we pass the triple test.\nCurrent object sizes are:\n\n```\n   806 Jun  4 10:11 targ6809.o\n   834 Jun  4 10:11 misc.o\n  1062 Jun  4 10:11 targqbe.o\n  2012 Jun  4 10:11 tstring.o\n  2112 Jun  4 10:11 opt.o\n  2658 Jun  4 10:11 detok.o\n  2733 Jun  4 10:11 detree.o\n  4399 Jun  4 10:11 types.o\n  5513 Jun  4 10:11 ctreeopt.o\n  5759 Jun  4 10:11 tree.o\n  5858 Jun  4 10:11 parse.o\n  7373 Jun  4 10:11 desym.o\n  7638 Jun  4 10:11 stmt.o\n  7868 Jun  4 10:11 cgen.o\n  8801 Jun  4 10:11 sym.o\n 11590 Jun  4 10:11 gen.o\n 13256 Jun  4 10:11 wcc.o\n 13942 Jun  4 10:11 scan.o\n 17670 Jun  4 10:11 expr.o\n 19156 Jun  4 10:11 decl.o\n 21114 Jun  4 10:11 cgqbe.o\n 34268 Jun  4 10:11 cg6809.o\n```\n\n## Tue 04 Jun 2024 11:38:09 AEST\n\nI brought in some of the SubC tree optimisations.\nSome didn't work and are commented out. The overall\ncode reduction is minimal.\n\nDamn. I didn't check to later but they broke some of\nthe 6809 tests. Sigh.\n\n## Tue 04 Jun 2024 11:44:46 AEST\n\nI'm thinking of this idea, see this existing code:\n\n```\nL2:\n        ldd -2,u   <-- d_holds \"-2,u\"\n        cmpd #8\n        bge L3\n;\t\t   <- now NOREG due to free all locns\n        ldd -2,u\n```\n\nBut surely we could keep this one because then we\nwouldn't have to reload D? We would have to flush all\nlocations on a jump. I might see if I can do this.\n\nUrgh, the tests pass but the code size is worse!!\nI did add a simple peephole optimisation to avoid an\n`ldd` after `std` to the same location.\n\n## Tue 04 Jun 2024 13:25:58 AEST\n\nJust did another fcc vs. wcc size comparison:\n\n```\n                 fcc     wcc\ncg6809.o        28682   33364   1.16\ncgen.o          5587    7742    1.39\ncgqbe.o         16867   20999   1.24\nctreeopt.o      3965    5504    1.39\ndecl.o          14499   19058   1.31\ndesym.o         5881    7340    1.25\ndetok.o         1894    2609    1.38\ndetree.o        1848    2700    1.46\nexpr.o          11646   17527   1.50\ngen.o           8745    11482   1.31\nmisc.o          742     834     1.12\nopt.o           1519    2051    1.35\nparse.o         4265    5797    1.36\nscan.o          11312   13822   1.22\nstmt.o          5649    7596    1.34\nsym.o           6732    8781    1.30\ntarg6809.o      761     806     1.06\ntargqbe.o       903     1046    1.16\ntree.o          5152    5745    1.12\ntstring.o       2012    2012    1.00\ntypes.o         2516    4397    1.75\nwcc.o           10282   12897   1.25\n                        Average 1.29\n```\n\nSo 29% bigger than `fcc` at present.\n\nI'm just looking at `types.c`. The first function is:\n\n```\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n```\n\nwith the AST being:\n\n```\nFUNCTION inttype\n  RETURN\n    LOGAND\n      EQ\n        AND\n          IDENT rval type\n          INTLIT 15\n        INTLIT 0\n      LOGAND\n        GE\n          IDENT rval type\n          INTLIT 32\n        LE\n          IDENT rval type\n          INTLIT 64\n```\n\n`wcc` generates awful code! But this is wrong:\n\n```\n        ldd 4,u\n        anda #15\t<- Should be #00\n        andb #15\n```\n\nIt's because `printlocation()` can't tell with literals\nif we are doing an 8-bit, 16-bit or 32-bit operation.\nMaybe I need to change one of the arguments to indicate\nif I'm using A, B, D or Y? Done and it seems to work.\n\n## Thu 06 Jun 2024 08:20:21 AEST\n\nI've been struggling with producing better LOGAND and LOGOR\ncode, because the current code makes a lot of #0 and #1s\nand then tests them. We should just be able to jump to\nlabels like `cgcompare_and_jump()`. I split them into two\nfunctions, but I think I can merge them. Viz:\n\n```\n                 x || y                   x && y\n--------------------------------------------------------------\n        if (lhs true)  goto Ltrue   if (lhs false) goto Lfalse\n        if (rhs false) goto Lfalse  if (rhs false) goto Lfalse\nLtrue:  ldd #1; goto Lend\nLfalse: ldd #0\nLend:\n```\n\nReally only the first line is different. I just need to pass\na different AST op down on the first line.\n\n## Thu 06 Jun 2024 11:33:16 AEST\n\nAfter much frustration I think I've finally fixed it. Yes, all the\ntests still pass as does the triple test.\n\n## Fri 07 Jun 2024 08:40:20 AEST\n\nI realised that I could optimise:\n\n```\n#11\n        ldx %1,u\n        ldd 0,x\nwith\n        ldd [%1,u]\n```\n\nand ditto D stores, B loads and stores. I finally realised that\nthe peephole optimiser rules are whitespace sensitive. I now have\na test input file I can run to check if it's working.\n\nI've realised that I can move some of the code generation into\nthe peephole rules file. This will lessen the amount of C code\nin the code generator. Example, I could generate `a >> 24` as\n\n```\n\tldd _a\n\t; cgshr 24\n```\n\nand the optimiser can replace it with a few Y/D/A/B exchanges and clears!\n\n## Fri 07 Jun 2024 08:53:54 AEST\n\nI wrote a Perl script to compare the `.o` sizes against `fcc`:\n\n```\n    cg6809.o:\t1.07\n      cgen.o:\t1.30  *\n     cgqbe.o:\t1.15\n  ctreeopt.o:\t1.33\n      decl.o:\t1.05\n     desym.o:\t1.25\n     detok.o:\t1.38\n    detree.o:\t1.46\n      expr.o:\t1.21  *\n       gen.o:\t1.34  *\n      misc.o:\t1.12\n       opt.o:\t1.21\n     parse.o:\t1.33  *\n      scan.o:\t1.13\n      stmt.o:\t1.22  *\n       sym.o:\t1.17\n  targ6809.o:\t1.06\n   targqbe.o:\t1.16\n      tree.o:\t1.12\n   tstring.o:\t1.00\n     types.o:\t0.99\n       wcc.o:\t1.25\n     Average:\t1.19\n```\n\nI've starred the ones that are important.\n\n## Fri 07 Jun 2024 09:53:22 AEST\n\nI've been writing a few more peephole rules. But now I've\nseen this code:\n\n```\nchar *fred() { return(NULL); }\n\nint main() {\n  if (fred() != NULL) printf(\"fred was not NULL\\n\");\n  return(0);\n}\n---\nFUNCTION main\n  IF\n    NE\n      FUNCCALL fred\n      CAST 17\n        INTLIT 0\n---\n        lbsr _fred\t; Call fred\n        std R0+0\t; Store result\n        ldd #0\n        std R1+0\t; Store 0 in temp\n        ldd R0+0\t; Now do the compare?!\n        cmpd R1+0\n        beq L3\n```\n\nWhy can't we just `cmpd #0, beq L3`? Yes that works.\nNow have to work out why we are generating this code!\n\nAh it's because of the cast. I added code to `cgwiden()`:\nif the primary sizes are the same, do nothing.\n\nThis has brought the `wcc/fcc` ratios down:\n\n```\n      cgen.o:\t1.30  now 1.23\n      expr.o:\t1.21  now 1.12\n       gen.o:\t1.34  now 1.30\n     parse.o:\t1.33  now 1.28\n      stmt.o:\t1.22  now 1.10\n     Average:\t1.19  now 1.15\n```\n\n## Fri 07 Jun 2024 16:40:13 AEST\n\nI've written `objcompare` to compare function sizes. The worst\nbetween `fcc` and `wcc` are:\n\n```\nenumerateAST:\n   F/parse.o     85\n   W/parse.o    151 1.78 (ratio)\n\ngenlabel:\n     F/gen.o     15\n     W/gen.o     26 1.73\n\nmkastnode:\n    F/tree.o    133\n    W/tree.o    215 1.62\n```\n\nso I guess I check those out first.\n\n## Sat 08 Jun 2024 10:02:01 AEST\n\nI got an e-mail from Alan Cox about his recent inprovements with `fcc`.\nI told him about this project and offered to send him the code.\n\nWhile up at the arena I looked through all of `cg6809.c`. There's an\nawful lot of:\n\n```\n  int primtype= cgprimtype(type);\n  ...\n  switch(primtype) {\n    case P_CHAR:\n    ...\n    case P_INT:\n    ...\n    case P_POINTER:\n    ...\n    case P_LONG:\n    ...\n  }\n\n```\n\nWe could get `gen.c` to send in the `primtype`, but I'm actually thinking\nof getting in a character that represents the primary type. Then we could do:\n\n```\nint cgadd(int l1, int l2, char primchar) {\n\n  load_d(l1);\n  // Print out a pseudo-op\n  fprintf(Outfile, \"\\tadd%c \", primchar); printlocation(l2, 0, primchar);\n  cgfreelocn(l2);\n  Locn[l1].type= L_DREG;\n  d_holds= l1;\n  return(l1);\n}\n```\n\nThen the peephole optimiser can expand the pseudo-op with the actual code.\nThis would lose a heap of code from the code generator! There would be\nan issue with INTLITS. If we generated:\n\n```\n    ; Pseudo-op\n    addl #1234567\n```\n\nthe peephole optimiser would have to do the `>>8` etc. Could be a pain.\nAh, a possible solution. For byte and int literals I can just print then,\ne.g. `#2345`. For long literals I can print the top byte in decimal,\nthe second byte in decimal and the bottom 16 bits in decimal, e.g.\n\n```\n    ; Pseudo-op\n    addl #0 #18 #54919\n```\n\nThen the optimiser can match against them. Would mean a lot of rules I guess.\n\n## Sat 08 Jun 2024 10:11:45 AEST\n\nI've written some other notes. Time to bring them in.\n\n## Fix For and Continue\n\nCurrently we do\n\n```\nfor (PRE; COND; POST)\n  BODY\n```\n\nand convert to \n\n```\n  PRE\nLstart:\n  COND  (which could jump to Lend)\n  BODY\n  POST\nLend:\n```\n\nand the AST tree:\n\n```\n  GLUE\n  / \\\nPRE WHILE\n     /  \\\n   COND  \\\n        GLUE\n        /  \\\n     BODY POST\n```\n\nBut we don't use the middle child in the WHILE node. So we could build this\ntree:\n\n```\n  GLUE\n  / \\\nPRE WHILE\n   /  |  \\\nCOND  | BODY\n    POST\n```\n\nIn `genWHILE()` we can check for the presence of the middle child. If it's\nthere, we produce code:\n\n```\n  PRE\t(done elsewhere)\n  jump Lcond\nLstart:\n  POST\nLcond:\n  COND  (which could jump to Lend)\n  BODY\nLend:\n```\n\nNow, any `break` will go to `Lend` and any `continue` will go to `Lstart`\nand still do the post operation.\n\n## Other Ideas\n\nWould it be useful to have an `x_holds` tracker? It wouldn't add much\n`cg6809.c` code as we don't use it but it might help shave a few percent\noff the code output.\n\nWe need `cgshrconst()`. \n\nFor shifts, we should check if the right is an INTLIT\nand use `cgshlconst()` and `cgshrconst()` for certain\nvalues.\n\nFor values 8, 16 and 24, just write a comment in the\nassembly code: `leftshift_8` for example. Use the\npeephole optimiser to put the code in. This means\nwe move lines of code out of the generator and into\nthe peephole optimiser. We could even do 1 and 2!\n\nFor the 8, 16, 24, we can do a bunch of register\nexchanges and clearing to get the work done.\n\n## Sun 09 Jun 2024 07:44:45 AEST\n\nAlan wrote back suggesting it would be better to add macros to\nthe assembler than to push pseudo-op expansion on the peephole\noptimiser. I guess that's true, especially as the optimiser loops\nback to see if it can apply more optimisations. It would be slow.\nAlan did mention tables, and I was wondering if I could use these.\n\nFor each \"operation\" there would be several size rules. Each rule\nwould have a string and an offset. If the offset is UNUSED, just\nprint the string, else print the string and the location with the\noffset.\n\nDo I just have a big table and a second table which holds the first\nentry to use and the number of lines?\n\nAnyway, before we even go there I still need to improve the code\ndensity and reduce the wcc/fcc size ratio.\n\n## Sun 09 Jun 2024 10:37:21 AEST\n\nSome more peephole rules. We now have:\n\n\n```\n      cgen.o:\t1.30  now 1.21\n      expr.o:\t1.21  now 1.10\n       gen.o:\t1.34  now 1.14\n     parse.o:\t1.33  now 1.27\n      stmt.o:\t1.22  now 1.06\n     Average:\t1.19  now 1.12\n```\n\n## Sun 09 Jun 2024 14:02:30 AEST\n\nMusing on the way to/from Bunnings, I thought about the temps being\non the stack. I just checked, they are always allocated in incrementing\norder and then either completely free or the last one is freed then\nall are freed. This means I can change the allocation algorithm to\njust increment a number.\n\nWhen they go on the stack I'll need to adjust the `localOffset` to\naccount for the temps. However, I won't know what the final value will\nbe until the end of the function.\n\nI was thinking, when doing `cgfuncpreamble(), I make the output file\nread/write. At the point where I'm going to emit the `leas` to adjust\nthe stack, I'll save the offset using `ftell() and emit:\n\n```\nfprintf(Outfile, \";\\tleas XXXXX,s\\n\");\n```\n\nLater on, if the `localOffset` is not zero, in `cgfuncpostamble()`\nI can `fseek()` back to this point and overwrite the line with the\nactual value. Slightly ugly but should work.\n\nFor now I'm going to change the temp allocation to just an increment.\nIt works; the new code is:\n\n```\nstatic int next_free_temp;\n\nstatic int cgalloctemp() {\n  return(next_free_temp++);\n}\n```\n\nLater on I'll keep a `highest_free_temp`. If we allocate past it,\nwe can bump `localOffset` up by four.\n\nWe definitely need to replace `u` as the frame pointer because this\nis adding a lot of extra code for really simple functions. It's why\n`fcc` is doing better with `parse.c`.\n\nIdea: we keep a `sp_adjust` variable, initally zero. Each time we\n`pshs` it goes up by the appropriate size. Down for `puls` or `leas`.\nAs with `fcc`, to begin with we can check that it is zero when we\nget to the function postamble.\n\nOn Tuesday I'll do the `sp_adjust` and lose the `u` frame pointer\nfirst. Once that's working I can move the temporaries on to the stack.\n\n## Sun 09 Jun 2024 14:48:20 AEST\n\nI decided to add the `sp_adjust` but keep the the `u` frame pointer\nas an intial step. I checked and `sp_adjust` is always zero in the\npostamble for all the code I can throw at it.\n\n## Sun 09 Jun 2024 14:57:49 AEST\n\nDamnit, I started on the code to lose the `u` frame pointer.\nUp to input026.c: OK, test 27 failed.\n\n## Sun 09 Jun 2024 15:30:10 AEST\n\nAnd ... done! It was actually easier than I expected. Just a few\ndumb things I should have changed which got fixed. All tests OK.\n\nWe now have as a comparison:\n\n```\n      cgen.o:\t1.18 size   6438\n      expr.o:\t1.04 size  12204\n       gen.o:\t1.06 size  10552\n     parse.o:\t1.23 size   5120\n      stmt.o:\t1.03 size   6047\n     Average:\t1.09\n```\n\nand the biggest `.o` files:\n\n```\n    cg6809.o:\t1.03 size  29498\n      decl.o:\t0.97 size  13901\n      expr.o:\t1.04 size  12204\n       gen.o:\t1.06 size  10552\n      scan.o:\t1.09 size  12365\n       wcc.o:\t1.17 size  12055\n```\n\n`wcc` is fine but the code generator is `cg6809.o` and `gen.o` plus\na bunch of others, so that's going to be the pain point.\n\n## Mon 10 Jun 2024 07:39:53 AEST\n\nI decided to try out the `ftell()`, `fseek()` code to patch in the\nstack change, just with the existing `leas` in the function preamble.\nIt works! Wow. Now I can get on with trying to put the temporaries on\nthe stack.\n\nAh, I'm stuck. Somehow we have to have some arrangement of:\n\n```\n  parameters\n  return address\n  locals\n  temporaries\n              <- sp\n```\n\nwith known offsets for them all. But until I've allocated the most\ntemporaries consecutively will I know how much room they require.\nThat means I can't work out the offsets for the locals and parameters.\nEven if I put the temporaries above the locals, I still can't work\nout the parameter offsets.\n\nCould I, when allocating a temporary, just add its size to `sp_adjust`\nand return 0 as the temporary's offset? Effectively I've pushed the\ntemporary on the stack. And then lower `sp_adjust` when we free all\ntemporaries.\n\n## Mon 10 Jun 2024 09:45:43 AEST\n\nYou know what. I just looked in `cg6809.c` and the spill code has been\ncommented out. So there's no need to spill temporaries. That means\nthere is no need to put them on the stack :-) Which means that I can\nkeep the current R0, R1 temporaries, yay! And I can lose the `fseek()`\ncode at the same time.\n\n## Mon 10 Jun 2024 09:59:13 AEST\n\nLet's now try to simplify the location allocation code in the same\nway that I did the temp allocation code. No, because `gen.c` often\nfrees all but one register, so I need to keep track of that one. Damn.\n\nI could copy the to-keep register down to R0, but it's a lot of effort.\nI'd have to rewrite the `gen.c` code to receive the new register's location.\nI'll park this for now.\n\n## Mon 10 Jun 2024 10:24:44 AEST\n\nNow going back to the table of output lines idea. I'll need to encode\noffset and \"register\" for printlocation:\n\n```\n      1 printlocation(0, 'a');\n      8 printlocation(0, 'b');\n     10 printlocation(0, 'd');\n      3 printlocation(0, 'e');\n      3 printlocation(0, 'y');\n      1 printlocation(1, 'b');\n      3 printlocation(1, 'f');\n      1 printlocation(2, 'a');\n      6 printlocation(2, 'd');\n      1 printlocation(2, 'y');\n      1 printlocation(3, 'b');\n```\n\nand if we need to do a printlocation on a line. \n\n## Mon 10 Jun 2024 11:45:59 AEST\n\nTaking a step back and looking at the function prototypes\nin `cg6809.c`, the ones I think I can tabulate have\none or two register arguments, a type and a label to jump to.\nMaybe I can alter `printlocation` to print nothing\nwhen it's not needed, and to print out a label.\n\nWhat I do need to do is to change the `type` that `gen.c`\nsends down to the `cgXXX.c` functions so we don't have to\nkeep converting it. I've made a start but it dies after\nsome tests.\n\n## Tue 11 Jun 2024 10:14:16 AEST\n\nAll 6809 tests now pass. I haven't rewritten the QBE backend yet.\nBy moving `cgprimtype()` up into `gen.c` I've saved 180 bytes\nwith the 6809 backend. Not much. It's probably not worth it,\nespecially if I have a table based approach where I can do the\n`cgprimtype()` twice and then use the tables for many operations.\nI'll park the changes in a side branch.\n\n## Wed 12 Jun 2024 13:47:19 AEST\n\nI added some `free()` code to `cgen.c` to clean up the AST trees.\nSometimes the left and right nodes are identical. Not sure why.\nAnyway that works. I tried to free the local and parameter symbol\nlists but now the QBE backend generates different code. So I've\ncommented this change out for now.\n\n## Wed 12 Jun 2024 14:12:56 AEST\n\nSo I decided to go crazy and try this:\n\n```\n$ sh -x z\nwcc -m6809 -o wcc wcc.c\nwcc -m6809 -o cscan scan.c misc.c\nwcc -m6809 -o detok detok.c tstring.c\nwcc -m6809 -o detree detree.c misc.c\nwcc -m6809 -o desym desym.c\nwcc -m6809 -o cpeep cpeep.c\nIncompatible types in binary expression on line 95 of cpeep.c\nwcc -m6809 -o ctreeopt ctreeopt.c tree.c misc.c\nwcc -m6809 -o cparse6809 decl.c expr.c misc.c opt.c parse.c stmt.c sym.c\n              tree.c targ6809.c tstring.c types.c\nwcc -m6809 -o cgen6809 cg6809.c cgen.c gen.c misc.c sym.c targ6809.c\n              tree.c types.c\n```\n\nwith the result:\n\n```\n-rwxr-xr-x 1 wkt wkt 12280 Jun 12 14:16 wcc\n-rwxr-xr-x 1 wkt wkt 10583 Jun 12 14:16 cscan\n-rwxr-xr-x 1 wkt wkt  7536 Jun 12 14:16 detok\n-rwxr-xr-x 1 wkt wkt  8984 Jun 12 14:16 detree\n-rwxr-xr-x 1 wkt wkt  8434 Jun 12 14:16 desym\n-rwxr-xr-x 1 wkt wkt  7941 Jun 12 14:16 ctreeopt\n-rwxr-xr-x 1 wkt wkt 27267 Jun 12 14:16 cparse6809\n-rwxr-xr-x 1 wkt wkt 29615 Jun 12 14:16 cgen6809\n```\n\nInteresting.\n\nDamn. `emu6809 ./cscan < detok.c_cpp > fred` produces\nand empty output file.\n\n## Wed 12 Jun 2024 15:34:38 AEST\n\nI just had an idea. The problem could be my own assembly output,\nor an interaction with libc, or the emulator not doing something\nright. But we do have another 6809 compiler, `fcc`. So I could\nbuild the binaries with `fcc` and see what happens.\n\nRight, I now have binaries built with `fcc`. This time `cscan`\ndoes produce output, but it goes into a loop around line 82\nof `detok.c` using the input file `detok.c_cpp`. At least the\n6809 `detok` binary works :-) Ah, `detok.c` only has 82 lines,\nso somehow it's not detecting the end of file.\n\nSo perhaps my emulator isn't sending EOF correctly?\n\nAlso checking that `fcc` passes my tests. No, test67 fails but\nthe others are OK.\n\n## Thu 13 Jun 2024 09:26:47 AEST\n\nI've added some debug code to `scan.c` and it looks like I've found\nan `fcc` bug:\n\n```\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\nfprintf(stderr, \"c is EOF, t->token is %d not %d\\n\", t->token, T_EOF);\n      return (0);\n```\n\nproduces the code:\n\n```\n        ldx #Sw67\n        bra __switch\nSw67_1:\n        clr [0,s]\t; Supposedly zero t->token, but\n        clr [1,s]\t; [0,s] is different to [8,s] below\n...\n        clra\n        clrb\n        pshs d\t\t; Push T_EOF which is zero\n        ldd [8,s]\n        pshs d\t\t; Push t->token\n        ldd #T176+0\n        pshs d\t\t; Push the string pointer\n        ldd #_stderr+0\n        pshs d\t\t; Push the FILE *\n        lbsr _fprintf+0\n```\n\nAnd, with my `wcc` compiling and building `cscan`, it looks like `fgetc()`\nreturns EOF on the first call. Very annoying.\n\n## Thu 13 Jun 2024 09:56:36 AEST\n\nI'm thinking of bring `fcc` and the bintools up to date with the Github\nrepo. Before I do that, here are the commits I am currently using:\n\n - bintools: bdb0076b5e3d4745aa08289d61e39f646d75805e\n - compiler: ffda85a94ce900423dc25a020fe62609ddcd46db\n\nI've got the lastest of both with the compiler at commit\n8a4b65b4d18be9528f3e5a6402b8e392e5ecc341. It runs the `wtests` OK\nbut it spitting out wrong code for some of the Fuzemsys libraries,\ne.g.\n\n```\n$ /opt/fcc/bin/fcc -m6809 -S -O -D__m6809__ clock_gettime.c\n$ vi +28 clock_gettime.s\n        lbsr __shrul\n        add 2,s\n        adc 1,s\n        adc ,s\n```\n\nwhich should be `addd, adcb, adca`. Now should I bother reporting\nthese to Alan? It means trying to find the commit that caused the\nproblem.\n\n## Fri 14 Jun 2024 11:24:25 AEST\n\nThe `fgetc()` problem with `wcc` was because I'd defined `stdin` as\na pointer not an array of one `FILE` struct. `cscan` is now reading\ncharacters but it fails elsewhere.\n\n## Fri 14 Jun 2024 12:01:11 AEST\n\nArgh! In the 6809 `cgswitch()` we are given the register (location)\nthat holds the switch value, but it was not being loaded into D.\nA simple `load_d(reg)` fixed this. I added test 160.\n\n## Fri 14 Jun 2024 12:17:20 AEST\n\nWe have progress. `cscan` and `detok` work and it looks like I'm making\na correct token stream file. The only issue is that it looks like the\nFuxiz `printf()` works differently than the Linux one, as I see these\nsort of differences:\n\n```\n6464c6375\n< 36: struct\n---\n> 27: struct\n6469d6379\n< 43: filename \\\"decl.c\\\"\n6472c6382\n< 36: void\n---\n> 1e: void\n6476d6385\n< 43: filename \\\"decl.c\\\"\n6480c6389\n< 36: struct\n---\n> 27: struct\n```\n\nThe token numbers being printed are different but the Tstring used is\ncorrect. And the double quotes in filenames are being quoted!\n\nActually that's not quite the truth. I had to make this change in `detok.c`:\n\n```\n<     *s++ = (char) ch;\n---\n>     *s = (char) ch; s++;\n```\n\nso I should investigate why as I can pass the QBE triple test with the\noriginal line. OK that was an easy fix, thankfully.\n\n## Fri 14 Jun 2024 12:42:40 AEST\n\nAh, I worked out why the token numbers were wrong. It seems that `cscan`\nisn't detecting any keywords but converting everything to a STRLIT.\nThat's why I'm getting:\n\n```\n$ emu6809 cparse6809 decl.c_sym decl.c_ast < decl.c_tok \nunknown type:void on line 4 of /opt/wcc/include/6809/stdlib.h\n```\n\nas that's \"void\" not 30 (T_VOID).\n\n## Fri 14 Jun 2024 15:19:25 AEST\n\nIt's because `if (!strcmp(...))` isn't working. Fixed.\n\n## Sat 15 Jun 2024 09:32:15 AEST\n\nNot fixed. It's because we are returning from a switch case. I have\na new test:\n\n```\nint keyword(char *s) {\n\n  switch (*s) {\n    case 'b': return(1);\n    case 'c': if (!strcmp(s, \"case\")) return(2);\n              return(3);\n    case 'v': if (!strcmp(s, \"void\")) return(4);\n              return(5);\n    default: return(6);\n  }\n  return(0);\n}\n```\n\nwhich works for QBE but always returns 6 with the 6809 backend.\nFixed now. The assembly code handling switch cases expects the\nargument to be `int` but we were sending it a `char` with garbage\nin the A register. I've changed `stmt.c` to widen a P_CHAR tree\nto be P_INT if required.\n\nIt looks like the token streams are now good with T_VOID for \"void\" etc.\n\nMoving on to the next phase:\n\n```\n$ emu6809 cparse6809 decl.c_sym decl.c_ast < decl.c_tok\nunknown struct/union type:FILE on line 35 of /opt/wcc/include/6809/stdio.h\n```\n\nLooks like somehow the symbol table is getting mangled:\n\n```\nSearching for struct __stdio_file: missing!\nAdding struct __stdio_file\nSearching for struct __stdio_file: found it\nSearching for struct __stdio_file: missing!\n```\n\nWith more debug prints:\n\n```\nSearching for __stdio_file in list 778e class 0\nComparing against __stdio_file\n  (and found it)\n...\nSearching for __stdio_file in list 778e class 0\n  Did not find __stdio_file\n```\n\nwhere 778e is the head's value in hex and also\nwhere the name pointer lives (it's the first member\nof the struct). My debug code is:\n\n```\nfprintf(stderr, \"Searching for %s in list %lx class %d\\n\",\n\t\t\t\t\ts, (long)list, class);\n  for (; list != NULL; list = list->next) {\n    if (list->name != NULL)\n      fprintf(stderr, \"Comparing against %s\\n\", list->name);\n    if ((list->name != NULL) && !strcmp(s, list->name))\n      if (class == 0 || class == list->class)\n        return (list);\n  }\nfprintf(stderr, \"  Did not find %s\\n\", s);\n  return (NULL);\n```\n\nSo does this mean that `list->name` is being set to NULL somehow?\n\n## Sat 15 Jun 2024 11:14:39 AEST\n\nUsing the emulator and a write break, it looks like we are in\n`scalar_declaration()` at the top, doing `*tree = NULL;`. Which\nraises the question: are we not doing a double dereference, or how\nare we getting a pointer into the struct table?\n\nEven worse, that `tree` is a `struct ASTnode **` not even a symbol\ntable pointer! Argh!\n\n## Sat 15 Jun 2024 11:42:43 AEST\n\nI've got a `debug` file and I'm searching for 778E. I can see\na `newsym()` being made. I can see we go into `composite_declaration()`,\nfind the `rbrace()` and add a member to the struct.\n\n## Sat 15 Jun 2024 12:24:59 AEST\n\nStepping back a bit, I can compile this program with the 6809-binary phases:\n\n```\nvoid printint(int x);\nint main() { printint(5); return(0); }\n```\n\nso maybe I should just try compiling the test programs?\n\n## Sat 15 Jun 2024 12:45:54 AEST\n\nI have a test script now for this. Tests 1 and 2 are OK, 3 fails.\n\nThe 6809 `cparse6809` runs and creates outputs. So does the native\nversion of the compiler. The latter produces this symbol table:\n\n```\nint printf() id 1: global, 1 params, ctypeid 0, nelems 1 st_posn 0\n    char *fmt id 2: param offset 0, size 2, ctypeid 0, nelems 1 st_posn 0\nvoid main() id 3: global, 0 params, ctypeid 0, nelems 0 st_posn 0\nint x id 4: local offset 0, size 2, ctypeid 0, nelems 1 st_posn 0\nunknown type x id 0: unknown class, size 0, ctypeid 0, nelems 0 st_posn 0\n```\n\nThe last line is the empty symbol to mark the end of one AST tree.\nThe tree looks like:\n\n```\nFUNCTION main\n  ASSIGN\n    INTLIT 1\n    IDENT x\n  FUNCCALL printf\n    STRLIT rval \"%d\n\"\n    IDENT rval x\n  ASSIGN\n    ADD\n...\n```\n\nNow, doing the same with the 6809 tools:\n\n```\nint printf() id 1: global, 1 params, ctypeid 0, nelems 1 st_posn 0\n    char *fmt id 2: param offset 0, size 2, ctypeid 512, nelems 1 st_posn 0\nvoid main() id 3: global, 0 params, ctypeid 0, nelems 0 st_posn 0\nint x id 4: local offset 0, size 2, ctypeid 4, nelems 1 st_posn 0\nunknown type  id 0: unknown class, size 0, ctypeid 0, nelems 0 st_posn 0\n```\n\nand\n\n```\nFUNCTION main\nUnknown dumpAST operator:8745 on line 1 of\n```\n\nWith some more debug code, the two `detree`s do:\n\n```\n      Native\t\t    6809 binary\nNext ASTnode op 32      Next ASTnode op 32\nAbout to read in a name About to read in a name\nWe got main     \tWe got main\nNext ASTnode op 29      Next ASTnode op 29\nNext ASTnode op 29      Next ASTnode op 29\nNext ASTnode op 29      Next ASTnode op 29\nNext ASTnode op 29      Next ASTnode op 29\nNext ASTnode op 29      Next ASTnode op 29\nNext ASTnode op 29      Next ASTnode op 29\nNext ASTnode op 29      Next ASTnode op 29\nNext ASTnode op 29      Next ASTnode op 29\nNext ASTnode op 29      Next ASTnode op -31959\n```\n\nJust checked, there are nine `op 29` nodes in sequence. Why\nare we not reading this? Perhaps its a stdio problem. That's the\nninth 32-byte record we read in, and it seems we read in:\n\n```\n2B3E: D7 29 D2 28 D2 28 D2 29 D2 00 03 00 5D 00 00 00   .).(.(.)....]...\n2B4E: 00 00 00 00 00 00 00 24 85 00 53 00 00 00 00 00   .......$..S.....\nwhereas before we were getting\n2B62: 00 1D 00 00 00 00 00 00 74 A8 00 00 73 F4 00 09   ........t...s...\n2B72: 00 0A 00 00 00 13 00 00 00 00 00 00 00 00 00 00   ................\n```\n\nand 0x001D is op 29.\n\n## Sat 15 Jun 2024 14:09:01 AEST\n\nOK it's an input issue. Here's the two records using `hd`:\n\n```\n00000100                    1d 00  00 00 00 00 00 74 a8 00\n00000110  00 73 f4 00 09 00 0a 00  00 00 13 00 00 00 00 00\n00000120  00 00 00 00 00 00 1d 00  00 00 00 00 00 6f 90 00\n00000130  00 74 cc 00 0a 00 0b 00  00 00 0e 00 00 00 00 00\n00000140  00 00 00 00 00 00\n```\nand a dumb dump of the file:\n\n```\nop 1d type 0 ctype 0 rvalue 0 left 74a8 mid 0 right 73f4 nodeid 9\nleftid a midid 0 righid 13 sym 0 name NULL symid 0 size 0 linenm 0\n\nop     5823 type   5322 ...\n```\n\n## Sun 16 Jun 2024 10:24:16 AEST\n\nBack again today with a cold. I've changed the code to just dump\nthe buffer in hex. Using both `fcc` and `wcc` I get the same\nbehaviour of getting gibberish. Interestingly, if I remove the\ncode that calls my `fgetstr()` function, it works fine and doesn't\nprint any gibberish.\n\nHah. I rewrote the code from scratch and it still fails. Then I\ndecided to remove the `fgetc()` and replace with `fread()` and now\nit works. So either `fgetc()` itself is bad or the code (compiled\nby `fcc`) is bad. Or, it's an interaction between `fgetc()` and `fread()`.\n\n## Sun 16 Jun 2024 10:59:40 AEST\n\nSEE BELOW...\n\nThat helped a lot! I can now pass lots more tests. Tests 1 to 10 OK,\n11 fails, 12 to 21 OK, 22 fails, 23 to 25 OK.\n\nI guess I can compare the assembly files and see how they differ.\nActually I can also do the AST and symbol files. The AST files are\nfine. But for the symbol files I see this:\n\n```\n$ diff sym 6sym\n2c2\n<     char *fmt id 2: param offset 0, size 2, ctypeid 0, nelems 1 st_posn 0\n---\n>     char *fmt id 2: param offset 0, size 2, ctypeid 512, nelems 1 st_posn 0\n4,7c4,7\n< int i id 4: local offset 0, size 2, ctypeid 0, nelems 1 st_posn 0\n< char j id 5: local offset 0, size 1, ctypeid 0, nelems 1 st_posn 0\n< long k id 6: local offset 0, size 4, ctypeid 0, nelems 1 st_posn 0\n< unknown type k id 0: unknown class, size 0, ctypeid 0, nelems 0 st_posn 0\n---\n> int i id 4: local offset 0, size 2, ctypeid 4, nelems 1 st_posn 0\n> char j id 5: local offset 0, size 1, ctypeid 5, nelems 1 st_posn 0\n> long k id 6: local offset 0, size 4, ctypeid 6, nelems 1 st_posn 0\n> unknown type  id 0: unknown class, size 0, ctypeid 0, nelems 0 st_posn 0\n```\n\nand the ctypeids are all wrong. Yes, they are in the actual sym file.\nI added some debug code to `newsym()` to see what the `ctype` pointer\nis set to. With the native compiler:\n\n```\nnewsym printf ctype (nil) ctypeid 0\nnewsym fmt ctype (nil) ctypeid 0\nnewsym main ctype (nil) ctypeid 0\nnewsym i ctype (nil) ctypeid 0\nnewsym j ctype (nil) ctypeid 0\nnewsym k ctype (nil) ctypeid 0\n```\n\nand the 6809 version:\n\n```\nnewsym printf ctype 00000 ctypeid 0\nnewsym fmt ctype 00003 ctypeid 512\nnewsym main ctype 00000 ctypeid 0\nnewsym i ctype 00002 ctypeid 4\nnewsym j ctype 00002 ctypeid 5\nnewsym k ctype 00002 ctypeid 6\n```\n\nand I doubt 2 and 3 are real pointers in memory!\n\n## Sun 16 Jun 2024 11:52:03 AEST\n\nHmm. Some printfs later:\n\n```\nd_l B2 ctype 00000\ns_d ctype 00002\nnewsym i ctype 00002 ctypeid 4\n```\n\nIt looks like I'm not correctly passing the `ctype` to\n`symbol_declaration()`. Yes, this doesn't look right:\n\n```\n        leax 6,s\n        tfr x,d\n        ldd [10,s]\n        pshs d\n        ldd 14,s\n        pshs d\n        pshs d\t\t<-- Push twice with no D change?!\n        ldd 8,s\n        pshs d\n        lbsr _symbol_declaration\n        leas 8,s\n```\n\nand the C code is\n\n```\nsym = symbol_declaration(type, *ctype, class, &tree);\n```\n\nIt seems I'm not loading the actual `*ctype` value before pushing it.\nThe AST tree has:\n\n```\n      FUNCCALL symbol_declaration\n        IDENT rval type\n        DEREF rval\n          IDENT rval ctype\n        IDENT rval class\n        ADDR tree\n```\n\nand there's a bunch of other DEREF IDENTs in the tree elsewhere, but\nthis is the only one where we are not doing the deref.\n\nNo, it looks like we get into `cgcall()` with two locations marked\nas D_REGS:\n\n```\n(gdb) p Locn[0]\n$4 = {type = 7, name = 0x0, intval = 0, primtype = 3}   <===\n(gdb) p Locn[1]\n$5 = {type = 2, name = 0x0, intval = 12, primtype = 2}\n(gdb) p Locn[2]\n$6 = {type = 7, name = 0x0, intval = 0, primtype = 3}   <===\n(gdb) p Locn[3]\n$7 = {type = 2, name = 0x0, intval = 2, primtype = 2}\n```\n\nI think I can see the problem. In `gen_funccal()` we\ngenerate the code to get all the argument values:\n\n```\n  for (i = 0, gluetree = n->left; gluetree != NULL; gluetree = gluetree->left) {\n    // Calculate the expression's value\n    arglist[i] =\n      genAST(gluetree->right, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    typelist[i++] = gluetree->right->type;\n  }\n```\n\nbut several `cg6809` functions allocate a L_DREG location:\n`cgwiden()`, `cgaddress()`, `cgderef()`. And on this line:\n\n```\nsym = symbol_declaration(type, *ctype, class, &tree);\n```\n\nI am getting the address of `tree` and dereferencing `ctype`!\nThus we have two locations which think they are L_DREG.\n\n## Sun 16 Jun 2024 13:23:23 AEST\n\nSEE ABOVE... That `fgets()` -> `fread()` change broke the tests so\nI've reverted it for now and kept a copy of the new code in RCS.\n\nI've added a `stash_d()` in `cgderef()` and now the assembly is:\n\n```\n        leax 6,s\n        tfr x,d\n        std R0+0\t&tree into R0\n        ldx 10,s\n        ldd 0,x\n        std R1+0\t*ctype in R1\n        ldd R0+0\t&tree pushed\n        pshs d\n        ldd 14,s\tclass pushed\n        pshs d\n        ldd R1+0\t*ctype pushed\n        pshs d\n        ldd 8,s\t\ttype pushed\n        pshs d\n        lbsr _symbol_declaration\nwhich is optimised to\n        leax 6,s\n        stx R0+0\t&tree into R0\n        ldd [10,s]\n        std R1+0\t*ctype in R1\n        ldd R0+0\n        pshs d\t\t&tree pushed\n        ldd 14,s\n        pshs d\t\tclass pushed\n        ldd R1+0\n        pshs d\t\t*ctype pushed\n        ldd 8,s\n        pshs d\t\ttype pushed\n        lbsr _symbol_declaration\n```\n\n## Sun 16 Jun 2024 13:54:28 AEST\n\nThat fixed the `ctype` bug. But it doesn't fix the `input011` problem.\nAt least now the trees and symbol tables are the same.\n\nIt looks like the compiler isn't emitting the right literal\nsub-values for longs:\n\n```\n$ diff goodqbe badqbe \n49c49\n< \tldy #0\n---\n> \tldy #30\n150c150\n< \tldy #0\n---\n> \tldy #1\n158c158\n< \tcmpy #0\n---\n> \tcmpy #5\n189,190c189,190\n< \tadcb #0\n< \tadca #0\n---\n> \tadcb #1\n> \tadca #1\n```\n\nIn particular, we seem to be using the low half of the value\nwhen we should be using the upper half.\n\nThats the const handling in `printlocation()` and it's the only\nplace where we do right shifts. I'll try and replace it with\nsome byte handling. Done (I'd written it on paper before) and\nnow we get up to test 31 FAIL. Actually that's error testing.\nWe are now up to test 58 fail :-)\n\n## Sun 16 Jun 2024 15:09:58 AEST\n\nThe error is `Bad type in cgprimtype::0 on line 15 of main`.\nThe symbol table is fine but the tree shows INTLIT differences:\n\n```\n  good\t\t   bad\nFUNCTION main   FUNCTION main\n  ASSIGN          ASSIGN\n    INTLIT 12       INTLIT 12\n    DEREF           DEREF\n      ADD             ADD\n        ADDR var2       ADDR var2\n        INTLIT 0        INTLIT 48\t<==\n  FUNCCALL printf FUNCCALL printf\n    STRLIT rval \"%d\"        STRLIT rval \"%d\"\n    DEREF rval      DEREF rval\n      ADD             ADD\n        ADDR var2       ADDR var2\n        INTLIT 0        INTLIT 48\t<==\n```\n\nwhich are the member offsets in a struct.\n\nYes they are in the file, I added some printfs to detree:\n\n```\nINTLIT node value 12\tINTLIT node value 12\nINTLIT node value 0\tINTLIT node value 48\nINTLIT node value 0\tINTLIT node value 48\nINTLIT node value 99\tINTLIT node value 99\nINTLIT node value 2\tINTLIT node value 48\nINTLIT node value 2\tINTLIT node value 48\nINTLIT node value 4005\tINTLIT node value 4005\nINTLIT node value 3\tINTLIT node value 48\nINTLIT node value 3\tINTLIT node value 48\nINTLIT node value 0\tINTLIT node value 48\nINTLIT node value 2\tINTLIT node value 48\nINTLIT node value 3\tINTLIT node value 48\nINTLIT node value 0\tINTLIT node value 48\nINTLIT node value 2\tINTLIT node value 48\nINTLIT node value 3\tINTLIT node value 48\nINTLIT node value 0\tINTLIT node value 0\n```\n\nI checked in `expr.c` where we build the INTLIT node:\n\n```\nright = mkastleaf(A_INTLIT, cgaddrint(), NULL, NULL, m->st_posn);\n```\n\nand both native and 6809 versions use the right position. So\nhow does it get corrupted to be 48? Ooh, I print the value\nafter the `mkastleaf()` and it's 48!!\n\n`mkastleaf()` is getting the 48!\n\nWe have another double push:\n\n```\n        ldx 4,s\n        ldd 20,x\t<- but not storing m->st_posn\n        lbsr _cgaddrint\n        pshs d\t\t<- push cgaddrint() result\n        ldd #0\n        pshs d\t\t<- push NULL\n        ldd #0\n        pshs d\t\t<- push NULL\n        pshs d\n        ldd #26\n        pshs d\t\t<- push A_INTLIT\n        lbsr _mkastleaf\n```\n\nQuestion: why is the `cgaddrint()` result being pushed before\nthe NULLs? Ah, I'd missed a D stash in `cgcall()`. Yay, fixed.\n\n## Mon 17 Jun 2024 07:49:35 AEST\n\nThis gets us up to input130 which fails!! This is doing\n\n```\nprintf(\"Hello \" \"world\" \"\\n\");\n```\n\nThe AST tree is:\n\n```\nFUNCTION \n  FUNCCALL printf\n    STRLIT rval \\\"Hello \\\"\n  RETURN\n    INTLIT 0\n```\n\nwhich isn't right. The three strings are in the token stream.\n\nSide node: `printf(\"My name is \\\"Warren\\\" you know!\\n\");`. `gcc`\ngives `My name is \"Warren\" you know!`. But my compiler gives\n`My name is \\\"Warren\\\" you know!`. That means my compiler is\ninterpreting the literal incorrectly, so I should fix it.\n\nFixed that, didn't fix test 130.\n\n## Mon 17 Jun 2024 08:26:02 AEST\n\nSo the native `wcc` concatenates strings fine:\n\n```\nFirst strlit >foo< totalsize 3 >foo< litend 0x56267086dfe3\nFirst strlit >Hello < totalsize 6 >Hello < litend 0x56267086e196\nNext strlit >world< totalsize 11 >Hello world< litend 0x56267086e19b\nNext strlit >\n< totalsize 12 >Hello world\n< litend 0x56267086e19c\n```\n\nbut the 6809 one doesn't:\n\n```\nFirst strlit >Hello < totalsize 6 litval 08574 >Hello < litend 0857a\nNext strlit >world< totalsize 11 litval 08564 >Hello < litend 0857f\nNext strlit >\n< totalsize 12 litval 08090 >Hello < litend 08580\n```\n\nOK, fixed. Now test 135 fails. Also, the only other test that fails is 162.\n\nThe symbol table and AST tree look fine.\nIt seems like the code generator is crashing. Looking at the debug trail,\nwe are in `cgcall()`. `ptrtype()` has returned 1 and `cgprimsize()` has\nreturned 2. We then do a `fprintf()`. So we must be doing this line:\n\n```\n  // Call the function, adjust the stack\n  fprintf(Outfile, \"\\tlbsr _%s\\n\", sym->name);\n```\n\nSingle-stepping the emulator, `sym->name` is fine, it points to \"printf\".\nThe string literal seems fine. And then we push $765E which the map file\nsays is Outfile. So it doesn't look like our code is wrong.\n\nWe fall into `vfnprintf()` and the switch statement for '%' with B holding\n0x73 i.e. 's'. We get down to:\n\n```\n   __switchc+0005: CMPB ,X+         | -FHI-Z-- 00:73 7572 0001 0000 FC89\n   __switchc+0007: BEQ $6410        | -FHI-Z-- 00:73 7572 0001 0000 FC89\n   __switchc+000F: LDX ,X           | -FHI---- 00:73 0007 0001 0000 FC89\n   __switchc+0011: JMP ,X           | -FHI---- 00:73 0007 0001 0000 FC89\n0007: LSR <$00         | -FHI---C 00:73 0007 0001 0000 FC89\n```\n\nand that jump to $0007 is definitely wrong! Here's a dump of the switch\ntable:\n\n```\n7536: 00 14 00 55 5D 2D 55 6B 20 55 73 2B 55 73 23 55\n7546: 7C 2A 55 84 2E 55 C2 6C 55 CA 68 55 D2 64 55 D9\n7556: 69 55 D9 62 56 27 6F 56 2E 70 56 35 58 56 4E 78\n7566: 56 55 75 56 5A 21 57 61 63 57 7F 73 00 07 58 06\n7576: FD 96 00 05 FF FF 00 00 00 00 00 00 00 04 00 02\n```\n\nLet's rewrite that a bit:\n\n```\n00 14     $14 (20 entries)\n00 555D   0: '\\0'\n2D 556B   1: '-'\n20 5573   2: ' '\n2B 5573   3: '+'\n23 557C   4: '#'\n2A 5584   5: '*'\n2E 55C2   6: '.'\n6C 55CA   7: 'l'\n68 55D2   8: 'h'\n64 55D9   9: 'd'\n69 55D9  10: 'i'\n62 5627  11: 'b'\n6F 562E  12: 'o'\n70 5635  13: 'p'\n58 564E  14: 'X'\n78 5655  15: 'x'\n75 565A  16: 'u'\n21 5761  17: '!'\n63 577F  18: 'c'\n73 0007  19: 's'  <== must have been tromped on\n   5806  default\n```\n\nYes, the jump should be to $57AC. Putting in some write breaks...\nIt looks like the offending code is at the end of `load_d()`:\n\n```\n     _load_d+$00C8: LBSR _mul\n     _load_d+$00CB: ADDD #$757C     base of Locn[]\n     _load_d+$00CE: TFR D,X\n     _load_d+$00D0: LDD #$0007      \n     _load_d+$00D3: STD ,X\n\nwhich is   Locn[l].type= L_DREG;\n```\n\nThe debug trace shows that `load_d()` is being called with -1 (NOREG)!\nLeading up to this, we are doing a `switch` on 0x22 in `genAST()`\nwhich is an A_RETURN.  `genAST()` loads NOREG and calls `cgreturn()`.\n\nAnd in the native version:\n\n```\nBreakpoint 1, cgreturn (l=-1, sym=0x555555566200) at cg6809.c:1211\n(gdb) s\nload_d (l=-1) at cg6809.c:154\n```\n\nHah! So `load_d()` is getting a NOREG! OK I added code in `cgreturn()`\nto not load D when NOREG. Test 135 passes now. And so does test 162.\nSo all the tests now pass. Yay!!!\n\n## Mon 17 Jun 2024 10:13:33 AEST\n\nNow we are down to these issues when building the compiler with\nitself:\n\n- Incompatible types in binary expression on line 95 of cpeep.c\n- Can't A_ASSIGN in genAST(), op:1 on line 180 of run_command\n\nThe first is pointer subtraction.\nThe second is, I think, because `stdin` on Fuzix is defined as\nan array not a pointer, so we can't assign a pointer to an array.\nAh, `freopen()` already resets the incoming file handle, no need\nto do the assign. That's fixed.\n\nNow I can put in a band-aid fix for just char pointer subtraction.\nI've done this, and I've added a test for it. All tests pass for:\ntriple test, QBE, 6809 and 6809 compiled compiler. Now we just need\nto pass the triple test on the 6809 side!\n\n## Mon 17 Jun 2024 14:47:53 AEST\n\nSo there is this line in `cpeep.c`:\n\n```\nnext = &((*next)->o_next);\n```\n\nwhich the compiler doesn't like: & operator must be followed by an\nidentifier on line 155 of cpeep.c.\n\nI guess I get to rewrite that line!\n\n## Mon 17 Jun 2024 14:52:55 AEST\n\nDamn. I'm going from the smallest file upwards with a script called\n`smake`. I hit:\n\n```\n$ ./smake  types.c\nDoing types.c\nUnable to malloc in mkastnode() on line 103 of types.c\n```\n\nBut the assembly files for these ones are OK:\ntstring.c, targ6809.c, tree.c, detok.c, opt.c. The only minor\nthing is:\n\n```\n$ diff detok.s S/detok.s \n536c536\n< \tldd #65535\n---\n> \tldd #-1\n```\n\nwhich I think is OK. It is: I made the `.o` file from both versions\nand they have the same checksum.\n\nDamn. So now we need to get on to saving memory!\n\n## Mon 17 Jun 2024 15:29:42 AEST\n\nI had this idea. Can we serialise (and then free) subtrees\nwhen we know that they are whole statements with no useful\nrvalue?\n\nI just wrote a `dumptree.c` which simply reads in and dumps\nAST nodes. At line 103 of `types.c` we are up to node 231,\nwith the function `modify_type()` starting at node 76.\nOn 6809 AST nodes are size 32, so that's 4,992 bytes.\n\nI also thought about how to `free()` AST nodes. I've tried\nin a few places with no luck, e.g. in `serialiseAST()` and\nin the `opt.c` functions. Sigh.\n\n## Tue 18 Jun 2024 08:52:10 AEST\n\nI added some `brk()/sbrk()` debug code in the 6809 emulator to\nsee how quickly the heap grows. Looking at who calls `malloc()`,\nhere is how many times it is called when compiling `types.c`\nbefore we run out of heap:\n\n```\n    241 mkastnode\n    460 newsym\n      5 serialiseSymtab\n    928 strdup\n```\n\nI added some `free()`s in `decl.c` to help with the `strdup()`s\nin there. Just checked with the native compiler and, yes, there are\n460 symbols in the symbol table. Yikes!\n\n## Tue 18 Jun 2024 09:27:49 AEST\n\nHah! I didn't realise/remember that the compiler can have unions\nin structs:\n\n```\ntypedef union { int x; char c; } fred;\ntypedef struct { int foo; char *name; fred combo; } jim;\njim mynode;\n\nint main() {\n  mynode.foo= 12; mynode.name=\"Dennis\"; mynode.combo.x=17;\n  printf(\"%d %s %d\\n\", mynode.foo, mynode.name, mynode.combo.x);\n  return(0);\n}\n```\n\nMaybe I can put some data structures on a diet! I tried with the\nsymbol table with no success, sigh.\n\n## Wed 19 Jun 2024 10:13:08 AEST\n\nI've been trying to come up with a good idea for the symbol table.\nI think I have one.\n\nFirstly, when parsing we write out any non-local/param symbols to\nthe symbol table file as soon as possible and then free them.\n\nWe keep a single in-memory symbol table. The only things in this\ntable are symbols from the symbol table file that have been brought\nin by a `findXXX()` operation.\n\nIn global context, this in-memory table will hold, e.g. typedefs\nthat are used by other things, e.g.\n\n```\nextern FILE *stdin;\t// We need to know about FILE's size\n```\n\nIn a function context, the table will hold all the symbols that the\nfunction uses, including parameters and locals.\n\nAt the beginning of each function, we can free the list to get rid\nof anything built-up during global parsing. At the end of each\nfunction we can flush all the locals and parameters to the file and\nthen free the list.\n\nThis should keep the in-memory symbol table relatively small, but\nhelp to minimise the number of times we go back to the file to get stuff.\n\nI think we can keep most/all of the existing `sym.c` API, with a few\nnew functions to do the free/flush actions.\n\nI've made a new git branch: symtable_revamp, for this. I've installed\nthe exsting compiler binaries in `/opt/wcc`. Because this is going to\nbreak a heap of things, I'll make a new install area `/opt/nwcc`. That\nway I can compare the old symbol table and tree vs. when the new code\nis creating.\n\n## Wed 19 Jun 2024 18:00:54 AEST\n\nI've made a start at the new code. It isn't finished and it doesn't\ncompile yet. However, I feel that it's a good approach. I've got\nthe code to add symbols done, now I'm writing the code to find symbols.\nIt will be interesting to debug it and find out what mistakes I've\nmade and what situations I didn't forsee.\n\n## Fri 21 Jun 2024 07:39:23 AEST\n\nIt's at the point where the code compiles and runs. It doesn't work yet,\nof course. I've just got a known-good symbol table with:\n\n```\n$ wcc -m6809 -S -X gen.c\n$ /opt/wcc/bin/desym gen.c_sym > goodsym\n```\n\nso when I do the same with the new code I can compare. I've added a slew\nof `fprintf()`s to the code.\n\nThe code at present doesn't properly attach function params as members\nof the function symbol. I can fix that. I was thinking, perhaps, of\nadding the locals to the function symbol as well. There are places\nin the gen code which walk both lists, so it would make sense to have\nthem available attached to the function symbol.\n\n## Sat 22 Jun 2024 12:58:09 AEST\n\nSome progress but I think I've hit another problem. We now have two\nin-memory symbol lists, one for types (struct, union, enum, typedef)\nand the other for variables and functions. Things that have members\n(struct, union, enum, function) get their associated members (locals,\nparams for functions) added to a temp list and attached to the symbol.\n\nNow the problem. In the original compiler I defined these lists of \"classes\":\n\n```\n// Storage classes\nenum {\n  C_GLOBAL = 1,                 // Globally visible symbol\n  C_LOCAL,                      // Locally visible symbol\n  C_PARAM,                      // Locally visible function parameter\n  C_EXTERN,                     // External globally visible symbol\n  C_STATIC,                     // Static symbol, visible in one file\n  C_STRUCT,                     // A struct\n  C_UNION,                      // A union\n  C_MEMBER,                     // Member of a struct or union\n  C_ENUMTYPE,                   // A named enumeration type\n  C_ENUMVAL,                    // A named enumeration value\n  C_TYPEDEF,                    // A named typedef\n  C_STRLIT                      // Not a class: used to denote string literals\n};\n```\n\nbut this is conflating two ideas. For example, I can have a\n`static struct foo { ... };`, so that the `foo` type is visible only\nin this file.\n\nWhat I need are two values in each symbol table. One holds \nthat the symbol is a struct/union/enum/typedef (or not), and the\nother holds the symbol's visibility (global, extern, static).\n\nWe already have structural types:\n\n```\nenum {\n  S_VARIABLE, S_FUNCTION, S_ARRAY\n};\n```\n\nso maybe I add the struct/union/enum/typedef to this. Also the strlit?\nThen keep global/extern/static/local/member/param/enumval as the\nstorage classes? And rename it as visibility.\n\nThe last four will always be in the `member` list and their actual visibility\nwill be determined by their parent symbol.\n\nAlso note for enums: enum values don't belong to any specific enum type.\nAlso, enum type names don't really do anything, but we do have\nto prevent redefinitions of them. So both can be stored in the main symbol\ntable: enum types as types and enum values as global symbols.\n\n## Sun 23 Jun 2024 10:50:15 AEST\n\nI've done the above and I'm slowly working my way there. Right now we\ncan read in all the global prototypes, enums, structs etc. fine. It\ndies when we hit the first function with parameters. Hopefully not too\nhard to fix.\n\n## Mon 24 Jun 2024 09:41:38 AEST\n\nWell ... I think there's a problem. Example:\n\n```\nint fred(int a, int b, int c);\n\nint fred(int x, int y, int z) {\n  return(x+y+x);\n}\n```\n\nThe prototype gets written to the symbol table file with `a,b,c`.\nWe now get the actual function with different parameter names.\nWe could remove the old member list and add the new parameters,\nbut these won't get written out to disk. Or, if we did write\nthis out to disk, then now we have two entries in the symbol table\nfor the same function. And we can't go and patch in the new variable\nnames as the new names might be bigger than the old ones. Damn!\n\nI'm thinking of adding a function to invalidate an on-disk symbol.\nIt would use the existing `findSyminfile()` to re-find the symbol,\nthen write a -1 `id` to mark it invalid. Then we can write out the\nnew symbol. It's an ugly solution but I can't think of a better one\nat the moment.\n\n## Mon 24 Jun 2024 15:14:55 AEST\n\nI've added the invalidate code. Seems to work. Right now the code\nappears to write out symbols but not NULLing the Member pointers,\nas I'm getting a function with a struct's members as variables :-)\n\n## Tue 25 Jun 2024 09:12:08 AEST\n\nI was loading symbols + their members from disk but I'd forgotten\nto reset the Memb pointers to NULL once done. I've also noticed that\nI'm writing symbols back out to disk multiple times. They get loaded\nin as needed, then flushed (written) back at the end of a function. Damn!\n\nWe are now up to this line in `gen.c`:\n\n```\ntype = n->left->type;\n```\n\nand the error message:\n\n```\nNo member found in struct/union: :type on line 200 of gen.c\n```\n\nUp to here, the old/new parse trees are identical which makes me feel good!\n\n## Tue 25 Jun 2024 09:35:21 AEST\n\nI think I have to add some symbol searching by id. I've added some dump code\nfor the in-memory symbol tables. I see:\n\n```\nstruct ASTnode: struct id 302: global, ctypeid 0, nelems 0 st_posn 0\n    int op id 303: member, size 2, ctypeid 0, nelems 1 st_posn 0\n    int type id 304: member, size 2, ctypeid 0, nelems 1 st_posn 2\n!!! struct exit *ctype id 305: member, size 2, ctypeid 287, nelems 1 st_posn 4\n    int rvalue id 306: member, size 2, ctypeid 0, nelems 1 st_posn 6\n!!! struct nodeid *left id 307: member, size 2, ctypeid 302, nelems 1 st_posn 8\n!!! struct nodeid *mid id 308: member, size 2, ctypeid 302, nelems 1 st_posn 10\n!!! struct nodeid *right id 309: member, size 2, ctypeid 302, nelems 1 st_posn 1\n```\n\nThe `ctype` pointers are pointing to the wrong types as indicated by the `!!!`.\nWhen I load symbols in from disk, I'm loading the symbol and its members.\nWhat I should do is, if the `ctype` is not NULL, find the matching `ctypeid`\nsymbol and link it back in. Damn!!!\n\n## Tue 25 Jun 2024 11:27:27 AEST\n\nI've added more code to load in symbols by id, and to link `ctype` fields\nto the matching symbol. We can now get down to the last function in `gen.c`\nand, up to that point, the trees are identical. I still haven't dealt with\nthe repeated same symbol writing to the symbol file yet.\n\nOK found the problem with the last function in `gen.c`. I needed to NULL\nthe Functionid before looking for duplicate parameters. Without this,\nwe were checking against the parameters in the previous function!\n\nWe now generate the same AST tree as compared to the compiler before\nthe on-disk symbol table. Yay!\n\n## Tue 25 Jun 2024 12:21:45 AEST\n\nI fixed the duplicate on-disk symbols. As we are allocating ids\nincrementally, simply record the highest one that we wrote out\nand don't write ones at or below this id on the next round.\n\nNow I'm trying to parse all the other C files and I'm having troubles.\nSigh. I've gone to the tests to see if I can parse them. Just a\ncouple are causing problems.\n\nThey were when a function call had no arguments, then function had\nno parameters but it did have locals. That's because all the locals\nare on the member list after the parameters. I had to fix up the\nlogic to stop when we hit the first local.\n\n## Wed 26 Jun 2024 10:02:50 AEST\n\nI've decided, now that we can parse all the tests, to try and get the\ngenerator to run as well. I've got the generator code to compile,\nand now comparing the assembly output from old/new compiler.\n\n## Wed 26 Jun 2024 12:33:58 AEST\n\nAh, I wasn't generating the data for global variables. I've got the\ncode nearly working, but there are 10 tests still failing. It's sooo\nfrustrating!\n\n## Wed 26 Jun 2024 14:29:00 AEST\n\nNow I'm up to trying to deal with global string literals which appear\nin the symbol table after the variable they get assigned to. Tricky.\nI'll find a way I'm sure. Yes, output the strlits first then the\nnon-strlits. Sigh. All the 6809 tests now pass. Some of the QBE tests\nfail, and they look like strlits. So I'll need to fix that up.\n\n## Fri 28 Jun 2024 14:06:37 AEST\n\nI needed to `strdup()` the string value in `cgqbe.c`. All the tests\nnow pass on QBE and 6809. But the current parser is still balking\nat the compiler's own code.\n\nSo here is the code in `wcc.c` that we are failing on:\n\n```\nvoid addtmpname(char *name) {\n  struct filelist *this;\n  ...\n}\n```\n\nIn the parser, we have added the prototype for `addtmpname()` to the\nin-memory symbol table (i.e. with the parameter) and we are in the\nfunction's body. Now we are searching for the `struct filelist` type.\nIt's been flushed out of memory, so we need to load it back in.\n\nIn doing so, we have NULL'd `Membhead` and `Membtail`. Why? Because\nwe loaded the `struct filelist` in and then had to read its members.\nBut we needed the member list to append the local `this` variable\nafter the `name` parameter. Damn!!\n\n## Sat 29 Jun 2024 08:15:25 AEST\n\nI fixed the above by adding a private list just for `loadSym()` to\nuse when reading symbols in from the file. Now onto the next problem.\n\nThere's a line in `scan.c` which is `c = next();`. We seem to be finding\nthe `next` symbol as a variable. We are calling:\n\n```\nres= loadSym(sym, name, stype, id, 0, 1); // stype NOTATYPE, id 0\n```\n\nand getting back a member of a struct called `next`, not the function.\nSo there is some logic bug in `loadSym()` that needs fixing.\n\nYes. When we use `loadSym()` and there's no match, we skip the initlist.\nBut if it's a struct/union type, we don't skip the members. So, we leave\n`loadSym()`, then come back to `loadSym()` and it then reads the members\nin and compares against the name.\n\nSo, somehow we need to load the struct/union type and load but skip the\nmembers. OK that wasn't too easy. If we are searching for a name, then\nit's not a local, param or member. The first two are found by `findlocl()`\nand the members are loaded recursively by `loadSym()` itself. I just\nadded another condition in the IF statement. We can now parse `scan.c`\nbut the generator dies.\n\nHere are the current list of errors:\n\n```\ncg6809.c 6809:Duplicate local variable declaration:cmplist on line 1028 of cg6809.c\ncgqbe.c: Can't find symbol with id:549 on line 71 of cgpreamble\ncpeep.c: & operator must be followed by an identifier on line 155 of cpeep.c\ndecl.c:  Can't find symbol with id:503 on line 0 of (null)\ndesym.c: Unknown variable or function:dumpsym on line 221 of desym.c\nexpr.c:  Unknown variable or function:binexpr on line 156 of expr.c\ngen.c:   Can't find symbol with id:511 on line 30 of Lfalse\nscan.c:  Can't find symbol with id:350 on line 0 of (null)\nstmt.c:  Unknown variable or function:if_statement on line 355 of stmt.c\nsym.c:   Type mismatch: literal vs. variable on line 26 of sym.c\n```\n\nThe first is only a 6809-side problem. The others (apart from the `cpeep.c` one)\nseem to be a symbol which was invalidated but not replaced with a new definition.\n\n## Tue 02 Jul 2024 10:47:44 AEST\n\nArgh, getting frustrated. I think the parser is now working fine, now a\nproblem in the code generator. The AST tree stores the id of many symbols.\nHowever, if we invalidate a function's symbol, we set the id to -1 and store\na new version of it in the symbol table, with a new id. But the AST might\nstill have the old id. Example:\n\n```\ncgqbe.c:static void cgmakeglobstrs();\ncgqbe.c:  cgmakeglobstrs();\ncgqbe.c:static void cgmakeglobstrs() { ... }\n```\n\nThe first line will get a symbol put into the table. The second line\nwill use this id in the AST. The third line invalidates the symbol's\nid and replaces it with a new one, but the AST remains the same.\n\nI tried in `decl.c` to get the old id, invalidate that symbol,\nmake the new symbol and insert the old id. Fine, except that the\n`sym.c` code remembers the highest id we wrote out before, and it\nwon't write out the new symbol because the id \"has been already written\".\nDamn!\n\nAnd all this because we need to make sure that the function's variable\nnames are stored and they could be different to the prototype ones.\nIs there another way?\n\nI think I'm going to enforce that the prototype parameter names\nmust match the actual function parameter names. That way I can\navoid invalidating anything.\n\n## Tue 02 Jul 2024 11:28:58 AEST\n\nDone and I've removed all the invalidation code. Apart from the\n`cpeep.c` problem, all the other C files compile and we still\npass the tests.\n\nNow I need to add `-D` pre-processor handling to `wcc.c`. Done.\n\n## Tue 02 Jul 2024 11:47:40 AEST\n\nNow a problem with `FILE *Symfile = NULL;` in `sym.c` which\ndoesn't seem to get added to the symbol table. Solved by\nadding it to `data.h` like the other symbols that need to\nbe extern sometimes and sometimes not.\n\nNow I'm trying the triple test. We get into an infinite loop\nbut only on some inputs:\n\n```\n$ L1/nwcc -S gen.c\n$ L1/nwcc -S stmt.c\n$ L1/nwcc -S cgqbe.c    <---\n^C\n$ L1/nwcc -S wcc.c      <---\n^C\n$ L1/nwcc -S cg6809.c   <---\n^C\n$ L1/nwcc -S expr.c\n$ L1/nwcc -S decl.c\n```\n\nFor `wcc.c` the symbol tree and AST files are fine, `nwcc` versus `L1/nwcc`.\nSo it must be the code generator getting stuck.\n\nWe seem to get into an infinite loop while `Searching for symbol id 143\nin memory`.\n\n## Tue 02 Jul 2024 13:11:14 AEST\n\nNo I think I've been bitten by this bug again. In `cgen.c`:\n\n```\n  // Now do the non string literals\n  for (sym=Symhead; sym!=NULL; sym=sym->next) {\n      if (sym->stype== S_STRLIT) continue;\n```\n\nCan we continue and still get the `sym=sym->next` to work? Nope.\n\nI rewrote the code and, yay!!!! we now pass the triple test again. Phew!\n\n## Tue 02 Jul 2024 13:21:31 AEST\n\nI can build the 6809 compiler binaries again using `build6809bins`.\nThat means I'm now back to where I was at Mon 17 Jun 2024 trying to\n`smake types.c`.\n\nThe scanner works but I'm getting:\n\n```\nemu6809 6/cparse6809 misc.c_sym misc.c_ast\nNew parameter name doesn't match prototype:stream on line 51\nof /opt/wcc/include/6809/stdio.h\n```\n\nDamn! The executable sizes are:\n\n```\n6/cgen6809.map:   7BA9 B __end\n6/cparse6809.map: 77D6 B __end\n6/cscan.map:      2E70 B __end\n6/ctreeopt.map:   2258 B __end\n6/desym.map:      24AA B __end\n6/detok.map:      218E B __end\n6/detree.map:     26D2 B __end\n6/nwcc.map:       3951 B __end\n```\n\n## Wed 03 Jul 2024 08:06:08 AEST\n\nOK, it's the 6809 code which is wrong. In a new test, these lines:\n\n```\n  if (strcmp(c, c)) { printf(\"%s and %s are different\\n\", c, c); }\n  if (!strcmp(c, c)) { printf(\"%s and %s are the same\\n\", c, c); }\n```\n\nproduce:\n\n```\nFisherman and Fisherman are different\nFisherman and Fisherman are the same\n```\n\nand the problem goes back to before the symbol table rewrite.\n\nI think I can see the problem. The second one has this debug run:\n\n```\n     _strcmp+003E: LEAS 4,S         | -FHI---- 00:00 01E3 0001 1082 FDAC\n     _strcmp+0040: PULS PC,U        | -FHI---- 00:00 01E3 0001 0000 FDB0\n       _main+0032: LEAS 4,S         | -FHI---- 00:00 01E3 0001 0000 FDB4\n       _main+0034: CMPD #$0000      | -FHI-Z-- 00:00 01E3 0001 0000 FDB4\n       _main+0038: BNE $016A        | -FHI-Z-- 00:00 01E3 0001 0000 FDB4\n       _main+003A: LDD #$0001       | -FHI---- 00:01 01E3 0001 0000 FDB4\n       _main+003D: BRA $016D        | -FHI---- 00:01 01E3 0001 0000 FDB4\n```\n\n`strcmp()` returns. We compare against zero and load a one if it was zero\n(the negation). However, for the first call:\n\n```\n     _strcmp+003E: LEAS 4,S         | -FHI---- 00:00 01E3 0000 1082 FDAC\n     _strcmp+0040: PULS PC,U        | -FHI---- 00:00 01E3 0000 0000 FDB0\n       _main+000D: LEAS 4,S         | -FHI---- 00:00 01E3 0000 0000 FDB4\n       _main+000F: BEQ $0150        | -FHI---- 00:00 01E3 0000 0000 FDB4\n       _main+0011: LDD $1105        | -FHI---- 10:78 01E3 0000 0000 FDB4\n```\n\n`strcmp()` returns zero but the Z flag isn't set. Thus the `BEQ` operation\nisn't taken. So I need to do a `CMPD #$0000` before the `BEQ`, as per the\nsecond call. OK fixed now.\n\n## Wed 03 Jul 2024 08:43:20 AEST\n\nDamn. We are running out of memory when compiling a small file like `misc.c`:\n\n```\nDoing misc.c\nUnable to malloc member in loadSym() on line 27 of misc.c\ncparse6809 failed\n```\n\nThat's worse than before we revamped the symbol table. Why?!!\n\n## Wed 03 Jul 2024 10:30:58 AEST\n\nI've spent a bit of time with valgrind. I had forgotten some `free()`s\nin `sym.c`. When I put them in, I failed the triple test. Argh! It\nturned out that I was not initialising the `rvalue` field in the symbols\nand this, not the `free()`s was the problem. I can now pass the triple\ntest again, and valgrind now shows that most of the mem leaks are with\nthe AST.\n\nBack to using `smake` to get the 6809 compiler to compile itself.\nMuch slower now that we have them symbol table in a file.\n\nThis time we got up to `detree.c` before we ran out of memory.\nThat's better than before. But it now means that I need to try\nand free the AST nodes. I tried this before and failed. Damn.\n\nAh. I'd added it to the code generator which worked/works, but not\nthe parser. Just added it now and still pass the triple test.\n\nWow. For the parser, valgrind tells me that the mem leak has fallen\nfrom 100K to about 4K. Let's see if that helps with `smake`.\n\nWell, we got a bit further. This time we fail in the generator with\n`detree.c` but we can compile `desym.c`. We can parse `stmt.c` but\nfail in the generator.\n\nInterestingly, the assembly files that do get generated only differ\nwith this:\n\n```\ndesym.s\n582c582\n<       ldd #65535\n---\n>       ldd #-1\n```\n\nwhich is good. So now I think I need to do a valgrind on the code generator.\n\nAh, I was loading the globals but not freeing the unused ones properly.\nFixed and still pass the triple test.\n\n## Wed 03 Jul 2024 11:54:43 AEST\n\nSo with these improvements I can now `smake stmt.c` and `wcc.c`. After that:\n\n```\nUnable to malloc in mkastnode() on line 539 of scan.c, cparse6809 failed\nUnable to malloc in mkastnode() on line 519 of gen.c, cparse6809 failed\nUnknown variable or function:ftell on line 366 of sym.c, cparse6809 failed\nUnknown AST operator:14336 on line -1279 of binexpr, cgen6809 failed\nUnable to malloc in mkastnode() on line 86 of decl.c, cparse6809 failed\n```\n\nThe `malloc()` ones are when we have really big functions, so the AST\ntree is huge! And I guess there are a lot of symbols too. Do we try to\nput the structs on a diet? I don't think I can easily serialise the\npartial AST tree?\n\n## Wed 03 Jul 2024 13:10:42 AEST\n\nStruct dieting. symtable: some things could be chars not ints:\n - type, stype, class, st_hasaddr\n\nWe could also unionise ctype and ctypeid.\n\nFor the AST nodes:\n - these could be chars: type, rvalue\n - we could unionise the left/mid/right pointers and ids\n - we could unionise the sym pointer and the symid\n - do we need name if we can use sym->name?\n\n## Wed 03 Jul 2024 14:48:23 AEST\n\nMusing on partial AST trees ... In the generator we have `genfreeregs()`\nwhich signals that there's no result needed. This gets called when\ngenerating IF, WHILE, SWITCH, logical OR, logical AND and glue operations.\nMaybe in the parser we could somehow serialise trees at these points.\n\nWe also have ids in each AST node. We could do something similar with\nthe current symbol table tree. We could have a `loadASTnode()` function.\nEach time we need to go left/mid/right, we could `loadASTnode()` with\nthe id.\n\nMaybe something like the following:\n\n```\n// Given an AST node id, load that AST node from the AST file.\n// If nextfunc is set, find the next AST node which is a function.\n// Allocate and return the node.\nstruct ASTnode *loadASTnode(int id, int nextfunc);\n```\n\n## Wed 03 Jul 2024 16:27:09 AEST\n\nI'm now thinking that I can ditch the whole in-memory AST tree concept.\nInstead, keep the tree on-disk as the AST file and left/mid/right ids,\nwhich provide an implicit tree.\n\nOn the generator side, we simply use `loadASTnode()` each time we\nneed to traverse left/mid/right. On the parser side, we still make\nnodes in memory, but once they are filled in (that means: left/mid/right,\nhasaddr etc.) then we just write the node to disk and free it.\n\nI think it also means that I can use the existing AST file and start work\non the generator side. Once that's working, I can go back and change the\nparser side of things.\n\n## Thu 04 Jul 2024 16:37:19 AEST\n\nI've written but not tested the `loadASTnode()` code. I made a start\nchanging `gen.c` over to use it, but there are fiddly spots. I feel that\nI need to step back a bit and do some thinking first. There is some list\nwalking code in `gen.c`; in a few functions we iterate the same list\nmultiple times. I don't really want to `loadASTnode()` the same nodes\nmultiple times in the same function.\n\nI also need to think about the best places to `free()` AST nodes.\nSo I might put in some `free()`s first, get them working before I do\nthe `loadASTnode()` conversion.\n\n## Thu 04 Jul 2024 17:36:11 AEST\n\nI rewrote the `genAST()` code so that there was one return only at the end.\nI added code in `tree.c` to free a single AST node. At the end of `genAST()`\nI can free the left and middle AST node and pass the triple test. I can't\ndo that when I free the right-hand one. Need to investigate.\n\n## Fri 05 Jul 2024 15:38:36 AEST\n\nThat is fixed. Somehow right can get set to left, so we must check it isn't\nbefore freeing it.\n\nI have spent some time setting new variables `nleft, nmid, nright` to\nhold the sub-nodes. At present I'm just copying pointers but eventually\nI will use `loadASTnode()`. In CASE and function calls we do have to\ntraverse the node linked list twice; can't get out of it. So I'll just\nhave to suck up the multiple disk reads for now. Maybe later build a\ncache of some sort?\n\n## Tue 09 Jul 2024 14:00:37 AEST\n\nBack from the 3-day comedy cruise. I've rewritten `detree.c` to use\nthe `loadASTnode()` function. After fixing a few minor issues, it\nprints out the same tree as the old version. That gives me confidence\nthat the `loadASTnode()` function works.\n\nI just added `free()`s in `detree.c` and every single AST node and\nassociated name string gets free'd. That makes me very happy!!\n\n## Tue 09 Jul 2024 15:38:05 AEST\n\nI've added the `loadASTnode()` code to `gen.c` and it works up to the\nfirst SWITCH test. That's pretty good :-) Once I get all the tests to\npass I will go back and work on freeing all the nodes that get allocated.\n\n## Tue 09 Jul 2024 15:58:16 AEST\n\nI had missed one left node pointer reference which needed to be loaded\nwith `loadASTnode()`. Now all the tests pass, yay!!!\n\n## Wed 10 Jul 2024 07:39:53 AEST\n\nI spent some time using valgrind last night and I've added a bunch\nof `freeASTnode()` and friends to the code. We are down to about 3K\nof un-free'd memory. That's excellent.\n\nI think I'll stop on the code generation side. Now I need to work out,\non the parsing side, how to build AST nodes, write them to disk once\nI have all the child node ids, and then free them.\n\nThe hard bit is to find one (or a few) places where I can do this. Right\nnow I'm doing it at the end of each function, but that requires too much\nmemory on the 6809 for large functions. \n\n## Wed 10 Jul 2024 10:33:05 AEST\n\nI'm trying to move the enumeration of the AST nodes into `tree.c`, so\nthat a node gets an id when it's created. The problem is that I change\nthe tree structure in several places e.g. `optimise()` and I have to\nfind all the relinking and fix the child ids at the same time. Right\nnow for test 009 I have a set of AST nodes where a child node's id\nis in several parent nodes! Not a tree!\n\nFixed. I wasn't zeroing the node ids when the child pointer was NULL.\n\n## Thu 11 Jul 2024 14:13:17 AEST\n\nWith the new AST enumeration code, the tests pass for QBE and 6809.\nNow trying to do the triple test and it fails. Comparing the `gcc` output\n(Good) vs. the L1 output (Bad). The `cpp` file is fine. The symbol tables\nare the same.\n\nThe AST files are the same except that the string literals seem different.\nLooks like the newlines are getting corrupted, e.g.:\n\n```\nGood\n----\n00003d70  00 00 00 00 00 00 00 00  00 4f 75 74 20 6f 66 20  |.........Out of |\n00003d80  73 70 61 63 65 20 69 6e  20 63 6d 64 61 72 67 73  |space in cmdargs|\n00003d90  0a 00 23 00 00 00 10 00  00 00 00 00 00 00 00 00  |..#.............|\n\nBad\n---\n00003870  00 00 00 00 00 00 00 00  00 4f 75 74 20 6f 66 20  |.........Out of |\n00003880  73 70 61 63 65 20 69 6e  20 63 6d 64 61 72 67 73  |space in cmdargs|\n00003890  6e 00 23 00 00 00 10 00  00 00 00 00 00 00 00 00  |n.#.............|\n```\n\nNote the first byte on the last line: `0a` versus `6e`: `6e` is ASCII 'n'.\nAnd the compiler before the symbol table fix has:\n\n```\n00003870  00 00 00 00 00 00 00 00  00 4f 75 74 20 6f 66 20  |.........Out of |\n00003880  73 70 61 63 65 20 69 6e  20 63 6d 64 61 72 67 73  |space in cmdargs|\n00003890  0a 00 23 00 00 00 10 00  00 00 00 00 00 00 00 00  |..#.............|\n```\nwhich is fine. And commit 6b870ee2d... Date:   Wed Jul 10 10:20:32 is also\nfine. So at least I can narrow down the problem (I hope :-).\n\n## Thu 11 Jul 2024 14:59:05 AEST\n\nLooking at the diffs between the two sets of files, there is nothing that\nsticks out as being a problem. Sigh.\n\n## Thu 11 Jul 2024 15:10:40 AEST\n\nIt's weird. Here are some debug lines for reading/writing string literals\nfor both the `gcc` and `nwcc` passes in the triple test:\n\n```\n      1 Read in string >Out of space in cmdargs\n<\n      1 Dumping literal string/id >Out of space in cmdargs\n<\n```\n\nThis is the `gcc` parser. Newlines are OK. Now the code generator:\n\n```\n   1509 Read in string >Out of space in cmdargs\n<\n```\nAgain, fine. Now the `nwcc` compiled parser and generator:\n\n```\n      1 Read in string >Out of space in cmdargsn<\n      1 Dumping literal string/id >Out of space in cmdargsn<\n   1509 Read in string >Out of space in cmdargsn<\n```\n\nwhich is wrong.\n\n## Thu 11 Jul 2024 15:34:54 AEST\n\nAh, the problem is back in the scanner! The Good scanner shows:\n\n```\n34: \"Out of space in cmdargs\n\"\n```\n\nThe Bad scanner shows:\n\n```\n34: \"Out of space in cmdargsn\"\n```\n\n## Fri 12 Jul 2024 07:41:16 AEST\n\nI have been able to build a test case which abstracts some of the scanner\ncode and which exhibits the problem. Using the compiler from before the\non-disk symbol/AST changes, compared to the current one, I see this difference\nin the generated AST tree:\n\n```\n28,30d27\n<       CASE 110 ()\n<         RETURN ()\n<           INTLIT 10 ()\n```\n\nThe case statement in the switch is completely missing!\n\n```\n    switch (c) {\n      case 'n':\n        return ('\\n');\n    }\n```\n\nUsing my new `astdump` program, I can see that the right-hand AST child\nid is missing in the SWITCH node in the file:\n\n```\n31 SWITCH type 0 rval 0\n   line 14 symid 0 intval 1\n   left 30 mid 0 right 0\n```\n\nwhere the good version has right 37. Ah, I found it. In `stmt.c` I link\nthe case sub-tree to the SWITCH node, but I'd forgotten to set up the\nright-hand id. Fixed.\n\n## Fri 12 Jul 2024 11:40:05 AEST\n\nWe are still not passing the triple test. In another directory I've\nchecked out the last commit which does pass the triple test:\n50b82937c5da569b. I've just compiled (to asm) the compiler files\nwith both (Good/Bad), and now I can compare the intermediate file.\n\nThe token files are identical. Now looking at the `detree` outputs.\nThese are different: scan.c, cg6809.c, cgqbe.c.\n\nHmm, it looks like there are still missing case statements. Weird!\nFound it, I was building a linked list of case trees and I had\nforgotten to add in the child's nodeid along the way. We now pass\nthe triple test again!\n\nNow I can get back to trying to serialise and free the AST nodes\nin the parser.\n\n## Fri 12 Jul 2024 12:12:08 AEST\n\nI've made a start, but I'm not serialising some of the AST nodes\nin input001.c. Damn! Ah, fixed. I can now pass all the tests except\nfor the one with the error \"No return for function with non-void type\".\nI've had to comment out this test in the compiler, as I'm now freeing\nthe tree before I can check if there is a return!\n\nWow. We pass all the QBE tests, all the 6809 tests and the triple test!!!\nI wonder if `valgrind` can tell me the maximum amount of memory allocated\nat any point in time? Yes: https://valgrind.org/docs/manual/ms-manual.html\n\n## Fri 12 Jul 2024 16:44:40 AEST\n\nI just did a compile of the biggest compiler C file with the compiler.\nLooking at the AST file with a script:\n\n```\nSeen 165 vs. unseen 2264\n```\n\nwhich means, when we read in an AST node that has children, it is more\nlikely that we haven't seen the children then we have.\n\nAnd that means we should NOT seek back to the start of the file. Instead,\nwe should start from where we currently are, for the next search, and\nexit if we hit the same seek point. \n\nI think. What I should do is add some counters in the `loadASTnode()`\nfunction, change the search algorithm and see which is better.\n\n## Sat 13 Jul 2024 09:56:58 AEST\n\nOK, so I've built the 6809 compiler binaries with `build6809bins`. Now\nI'm running `smake` on all the compiler C files to generate assembly\nusing the 6809 compiler binaries. It's as slow as hell! It's taken about\n10 minutes and we are only up to line 145 in `cg6809.c`. I tried with\na couple of small files yesterday and the code generator died. This time\nI'm going to try to compile everything, move the `*_*` files into a\nsubdir, then do the same with the native compiler. Then I can compare\nthe intermediate files to see if/where there are differences.\n\nI'll definitely have to do an execution profile on the code generator\nto see where the main bottlenecks are.\n\nAfter about 30-40 minutes, we are still only halfway through the\ncode generation of `cg6809.c`! Compared to the native compiler, the\nonly difference I see so far is:\n\n```\n<       anda #0\n<       andb #0\n---\n>       anda #255\n>       andb #255\n```\n\nThat's excellent as that is a very small difference and should not\nbe too hard to track down. We are off to see the kids for lunch, so\nI can leave this running for several hours :-)\n\n## Sat 13 Jul 2024 16:02:42 AEST\n\nBack from the lunch. Damn. `smake` removes all the temp files at the\nstart, so everything is pretty much gone. But it also looked like all\nthe code generation phases failed. So I guess I can do them all again...\nLooks like the parser ran out of memory on this one:\n`Unable to malloc in mkastnode() on line 684 of gen.c` but none else so far.\n\n## Sat 13 Jul 2024 16:51:56 AEST\n\nInteresting. It looks like most of the code generation was successful, it's\njust that the code generator doesn't stop nicely. Maybe I should `exit(0)`\nat the end of `main()` instead of `return(0)`?\n\nI'm also seeing a few:\n\n```\n<       ldd #65535\n---\n>       ldd #-1\n```\n\nwhich I think I've mentioned before.\n\nSo we have to check/fix these things:\n\n - 65535 / 1\n - and 0 / 255\n - segfault at end of code generation\n\nOnce they are fixed, we need to improve the speed of the code generation.\nRight now I'm thinking of building a temp file which just consists of\na list of AST file offsets, one per node. To find AST node X, we multiply\nby 4 (or shift left 2), `fseek()` to that point in the file and read in\nthe long offset at that point. Then we can `fseek()` into the AST file\nto get the node. The biggest AST file has 4549 nodes, so that means the\nfile of offsets would be 18K long. Too big to keep as an in-memory array.\n\n## Sun 14 Jul 2024 12:40:56 AEST\n\nI just did a debug run of the 6809 `cgen` on `parse.c` as it's a decent\nsized file. Yes, `main()` returns and we go off into never never land.\nI'm also trying to see which function have the most instructions run.\nThe results are:\n\n```\n242540320 div16x16\n87457045 _fread\n34695064 _fgetstr\n26953031 boolne\n20521224 __mul\n10534645 _loadASTnode\n7960435 __minus\n6814620 __divu\n6150026 booleq\n4794607 boolgt\n4735523 boollt\n4630436 __syscall\n4594719 __not\n3479025 boolult\n2271540 _read\n```\n\nso, yes, I need to optimise `loadASTnode()`.\n\n## Sun 14 Jul 2024 13:15:23 AEST\n\nLooking at the reason for the crash, it seems like something is touching the\ncode in `crt0.s`. It should call `exit()` after `main()` returns, but I see:\n\n```\n       _main+0156: RTS              | -FHI-Z-- 00:00 8160 0000 0000 FD91\n      __code+0028: NEG <$54         | -FHI-Z-- 00:00 8160 0000 0000 FD91\n```\n\nand `crt0.s` starts at $100. So I think I need to run the emulator with\na write break around $128.\n\nHmm, it seems to be one of the `fclose()` operations just before the\n`return(0)` at the end of `main()`. Weird!\n\n## Mon 15 Jul 2024 07:47:03 AEST\n\nI just checked that `#65535` and `#-1` produce the same machine code,\nso that's something I can ignore. For now, I'll remove the two `fclose()`s\nand put in an `exit(0)` at the end of cgen.c. Done.\n\nI will defer the `and #0` / `and #255` thing as the compiler is too slow!\nI'll start writing the code to build the AST offset index file.\n\n## Mon 15 Jul 2024 11:03:18 AEST\n\nIt's done, and we pass the normal tests but not the triple test. However\nthat's a good result for 45 minutes of work, and it seems to run faster.\n\n## Mon 15 Jul 2024 12:09:33 AEST\n\nI think maybe my compiler has a bug with `sizeof()`. Part of the index\nbuilding code is:\n\n```\nvoid mkASTidxfile(void) {\n  struct ASTnode node;\n  long offset, idxoff;\n\n  while (1) {\n    // Get the current offset\n    offset = ftell(Infile);\n    fprintf(stderr, \"A offset %ld\\n\", offset);\n\n    // Read in the next node, stop if none\n    if (fread(&node, sizeof(struct ASTnode), 1, Infile)!=1) {\n      break;\n    }\n    fprintf(stderr, \"B offset %ld\\n\", offset);\n    ...\n```\n\nand what I'm seeing when I run the L1 code generator:\n\n```\nA offset 133032\nB offset -7491291578409943040\nA offset 133120\nB offset -7491311919375056895\nA offset 133208\nB offset 1\nA offset 133308\nB offset 0\n```\n\nI think I'm reading in more than I should be when I'm reading in the ASTnode.\nNo, actually it seems like it might be QBE. Looking at the ouput, we have:\n\n```\nC code\n------\n  struct ASTnode node;\n  long offset, idxoff;\n\nQBE code\n--------\n  %node =l alloc8 11\t88 bytes in size\n  %offset =l alloc8 1\n\nASM code\n--------\nsubq $40, %rsp\t\t??? should be 96 at least\nmovq %rdx, -8(%rbp)\t-8 is the offset position on the stack\nleaq -24(%rbp), %rdi\t-24 is the node position on the stack\n```\n\nThis seems to mean that `node` is only 16 bytes below `offset` on\nthe stack, even though it is 88 bytes in size. I've emailed the\nQBE list for ideas.\n\nHmm. I made `node` a pointer and `malloc()`d it at the top of the\nfunction, then `free()`d it at the end. Now I pass the triple test.\nSo yes it seems to be a QBE bug.\n\nNo, it's my bug. I got this reply on the QBE list:\n\n> I believe alloc8 is alloc aligned on 8 byte boundary, not alloc 8*arg\n> bytes. So alloc8 11 allocates 11, not 88 bytes, etc.\n\nSo I need to fix the QBE output to deal with this. TO FIX.\n\n## Mon 15 Jul 2024 15:13:00 AEST\n\nOn the 6809 side, in `tree.c`, if I do this:\n\n```\n  n->leftid= 0;\n  n->midid= 0;\n  n->rightid= 0;\n```\n\nthen we get:\n\n```\n        ldx 0,s\n        ldd 12,s\n        std 10,x\n        ldx 0,s\n        ldd 14,s\n        std 12,x\n        ldx 0,s\n        ldd #0\n        std 16,x\n```\n\nBut if the code is this:\n\n```\n  n->leftid= n->midid= n->rightid= 0;\n```\n\nthen we get:\n\n```\n        ldx 0,s\n        ldd #0\n        std 20,x\n        std R0+0\t<== Save the rvalue #0\n        ldd 0,s\n        addd #18\n        tfr d,x\n        std 0,x\t\t<== Should reload R0\n        ldd 0,s\n        addd #16\n        tfr d,x\n        std 0,x\t\t<== Should reload R0\n```\n\nwhich is incorrect. TO FIX!!!\n\nNow I'm doing an `smake` on all the compiler files.\nIt's definitely a lot faster! No crashes yet ...\nAnd it only too 16 minutes to compile all the files.\nNow to compare them.\n\n## Mon 15 Jul 2024 15:37:11 AEST\n\nWow. The only file that didn't compile was `gen.c`\nas we ran out of memory in the parser: `Unable to\nmalloc in mkastnode() on line 684 of gen.c`.\n\nThe only assembly file differences are the `#-1 / #65535`\nwhich is ignorable, and the `anda #0 / #255` problem\nwhich I must fix.\n\nSo, if I can fix the latter issue and find a way to not\nrun out of memory in the parser with `gen.c`, then I\nshould be able to pass the triple test on the 6809 :-)\n\n## Mon 15 Jul 2024 15:50:17 AEST\n\nI think the `and` problem is a bug in `printlocation()`\nwith a int literal and 'e' or 'f' as the third argument.\n\n## Tue 16 Jul 2024 09:21:25 AEST\n\nI think I found the problem. We are doing `Locn[l].intval & 0xffff`\nbut `intval` is a long. That forces the compiler to widen the `0xffff`.\nBut, on the 6809, this is a negative value, so it gets widened to\n`0xffffffff` not `0x0000ffff`. I'm trying a solution where I\ncast/save to an `int` variable first before I do the AND.\n\nYes, that seems to work. I'm now running `smake` again, this time\nI'm converting the assembly files to object files. Then I can\nchecksum them to see if they are identical.\n\nThe results are excellent with `gen.c` the only one that didn't\ncompile (parser runs out of memory):\n\n```\n143856ed08f470c9bc5f4b842dcc27bd  New/opt.o\n143856ed08f470c9bc5f4b842dcc27bd  opt.o\n18e04acd5b8e0302e95fc3c9cddcdac5  New/tree.o\n18e04acd5b8e0302e95fc3c9cddcdac5  tree.o\n1d42a151ccf415e102ece78257297cd9  New/tstring.o\n1d42a151ccf415e102ece78257297cd9  tstring.o\n43b84fc5d30ea22ceac9a21795518fc3  decl.o\n43b84fc5d30ea22ceac9a21795518fc3  New/decl.o\n45a18eb804fdc0c75f3207482ad8678a  detok.o\n45a18eb804fdc0c75f3207482ad8678a  New/detok.o\n57d10f0978232603854a6e18bf386cba  New/wcc.o\n57d10f0978232603854a6e18bf386cba  wcc.o\n76ed2bc3c553568d16880dfdd02053e7  New/parse.o\n76ed2bc3c553568d16880dfdd02053e7  parse.o\n88bfe3920d8f08d527447fef2c24dc3b  New/scan.o\n88bfe3920d8f08d527447fef2c24dc3b  scan.o\n8c24c919c06532977a68472c709c5e22  cg6809.o\n8c24c919c06532977a68472c709c5e22  New/cg6809.o\n8e4fd9f9e9923c20432ec7dae85965c5  expr.o\n8e4fd9f9e9923c20432ec7dae85965c5  New/expr.o\n8ed5104a4b18a1eb8dea33c5faf6c8bd  New/sym.o\n8ed5104a4b18a1eb8dea33c5faf6c8bd  sym.o\n9d11b1336597eaa6bcdac3ade6eb13ab  misc.o\n9d11b1336597eaa6bcdac3ade6eb13ab  New/misc.o\na5fba53af6d4ca348554336db9455675  New/types.o\na5fba53af6d4ca348554336db9455675  types.o\nbeb8414b95be6f0de7494c21b16e1c53  New/stmt.o\nbeb8414b95be6f0de7494c21b16e1c53  stmt.o\nc1e56e66055f7868ab20d13585a76eb0  cgen.o\nc1e56e66055f7868ab20d13585a76eb0  New/cgen.o\nca8699919c901ed658c0ce5e0eb1d8e8  detree.o\nca8699919c901ed658c0ce5e0eb1d8e8  New/detree.o\nd25a34d8dc2bb895b8c279d8946733c3  New/targ6809.o\nd25a34d8dc2bb895b8c279d8946733c3  targ6809.o\ndeca10b552285f2de5c10e70547fd2a6  desym.o\ndeca10b552285f2de5c10e70547fd2a6  New/desym.o\n```\n\nSo if I can write a suitable script, I should be able to pass the\ntriple test on the 6809 side :-)\n\n## Tue 16 Jul 2024 10:47:01 AEST\n\nI've rewritten `build6809bins` to make the 6809 binaries and\nalso make some front-end scripts which run the emulator on\nthe respective binary, so we have `native` executables. We\nneed this because the 6809 `wcc` will just run `cscan ...` not\n`emu6809 cscan ...`.\n\nBut it's weird. `wcc` runs some of the phases but not all of them:\n\n```\n$ L1/wcc -m6809 -S -X -v targ6809.c \nDoing: cpp -nostdinc -isystem /usr/local/src/Cwj6809/include/6809 targ6809.c \n  redirecting stdout to targ6809.c_cpp\nDoing: /usr/local/src/Cwj6809/L1/cscan \n  redirecting stdin from targ6809.c_cpp\n  redirecting stdout to targ6809.c_tok\nDoing: /usr/local/src/Cwj6809/L1/cparse6809 targ6809.c_sym targ6809.c_ast \n  redirecting stdin from targ6809.c_tok\n```\n\nand no code generation phase. I think for now I'll write a Perl version\nof `wcc` so that I can get the triple test done.\n\n## Tue 16 Jul 2024 11:35:05 AEST\n\nI've broken one of the long SWITCH statements in `gen.c` into two;\nhopefully this will allow the 6809 compiler to parse this without\nrunning out of memory. I've checked and we pass all the tests.\n\n`gen.c` now does compile using the L1 6809 compiler, and the resulting\nobject file is identical to that made by the native compiler. I've\nhad to put the SWITCH split in an `#ifdef` as the change stopped the\nQBE triple test from passing. Weird!\n\n## Tue 16 Jul 2024 14:09:06 AEST\n\nI've written a Perl version of the `wcc` front-end, basically by\ntransliterating it. It now goes into the `L1` directory. I've just\nmodified `build6809bins` to build the `L2` binaries using the `L1`\n6809 compiler binaries. So far the `L2` files that have been built\nhave the same checksum as the ones in `L1`, but it's still going ...\n\n## Tue 16 Jul 2024 14:25:05 AEST\n\nOh, we came _sooo_ close!\n\n```\n$ md5sum L?/_* | sort \n0778e984e25d407d2067ac43d151d664  L2/_cgen6809  # Different\ne47a9ab1ed9095f1c4784247c72cb1f8  L1/_cgen6809\n\n0caee9118cb7745eaf40970677897dbf  L1/_detree\n0caee9118cb7745eaf40970677897dbf  L2/_detree\n2d333482ad8b4a886b5b78a4a49f3bb5  L1/_detok\n2d333482ad8b4a886b5b78a4a49f3bb5  L2/_detok\nd507bd89c0fc1439efe2dffc5d8edfe3  L1/_desym\nd507bd89c0fc1439efe2dffc5d8edfe3  L2/_desym\ne78da1f3003d87ca852f682adc4214e8  L1/_cscan\ne78da1f3003d87ca852f682adc4214e8  L2/_cscan\ne9c8b2c12ea5bd4f62091fafaae45971  L1/_cparse6809\ne9c8b2c12ea5bd4f62091fafaae45971  L2/_cparse6809\n```\n\nand that's because, at the linker phase:\n\n```\ncgen.c_o: Unknown symbol '_genglobstr'.\ncgen.c_o: Unknown symbol '_genglobsym'.\ncgen.c_o: Unknown symbol '_genpreamble'.\ncgen.c_o: Unknown symbol '_genAST'.\ncgen.c_o: Unknown symbol '_genpostamble'.\ngen.c_o: Unknown symbol '_genAST'.\n```\n\nDamn!!\n\nI'll build the asm files for the C files that make the code generator,\nusing the native and the 6809 L1 compilers, and compare.\n\n## Wed 17 Jul 2024 13:30:26 AEST\n\nI've spent the last day writing the Readme.md for the next part of the\n'acwj' journey. So far about 7,000 words and a couple thousand more to\ngo.\n\nI think the 6809 `gen.c` problem was that I forgot to do `-DSPLITSWITCH`\nwhen I compiled `gen.c`. Yes, now I have the same assembly except for\nthe -1 / 65535 change. Let's try the triple test again!\n\n## Wed 17 Jul 2024 13:59:56 AEST\n\nOK, I think I've passed the 6809 triple test:\n\n```\n$ md5sum L1/_* L2/_* | sort\n01c5120e56cb299bf0063a07e38ec2b9  L1/_cgen6809\n01c5120e56cb299bf0063a07e38ec2b9  L2/_cgen6809\n0caee9118cb7745eaf40970677897dbf  L1/_detree\n0caee9118cb7745eaf40970677897dbf  L2/_detree\n2d333482ad8b4a886b5b78a4a49f3bb5  L1/_detok\n2d333482ad8b4a886b5b78a4a49f3bb5  L2/_detok\nd507bd89c0fc1439efe2dffc5d8edfe3  L1/_desym\nd507bd89c0fc1439efe2dffc5d8edfe3  L2/_desym\ne78da1f3003d87ca852f682adc4214e8  L1/_cscan\ne78da1f3003d87ca852f682adc4214e8  L2/_cscan\ne9c8b2c12ea5bd4f62091fafaae45971  L1/_cparse6809\ne9c8b2c12ea5bd4f62091fafaae45971  L2/_cparse6809\n```\n\nAll the binaries' checksums match!! I still don't have the 6809 `wcc`\nbinary working, so I'm relying on the Perl version. But I've been\nable to compile the rest of the compiler's code with itself. Yayy!!!\n\n## Thu 18 Jul 2024 09:52:53 AEST\n\nI'm trying to work out why the 6809 `wcc` binary is failing. It runs\nthe C preprocessor (a native x64 binary) OK. Then it forks and runs\nthe 6809 `cscan` fine. Then it forks and runs the 6809 `cparse`.\nThis runs and completes; then `wcc` crashes with an unknown page-0 op.\nAh, I added an `exit(0)` before the final return which helps. Now\nit crashes running the peephole optimiser.\n"
  },
  {
    "path": "64_6809_Target/docs/copt.1",
    "content": ".de DS\n.nf\n.in +3\n.sp\n..\n.de DE\n.sp\n.in -3\n.fi\n..\n.TH copt 1\n.SH NAME\ncopt \\- peephole optimizer\n.SH SYNOPSIS\n\\fBcopt\\fP [-d] \\fIfile\\fP ...\n.SH OPTIONS\n.TP\n.B \\-\\^d\nTurn on debug modus. Replacements of original patterns\nwill be sent to stderr in the order of execution.\n.SH DESCRIPTION\n\\fIcopt\\fP is a general-purpose peephole optimizer.\nIt reads code from its standard input\nand writes an improved version to its standard output.\n\\fIcopt\\fP reads the named files for its optimizations,\nwhich are encoded as follows:\n.DS\n<pattern for input line 1>\n<pattern for input line 2>\n ...\n<pattern for input line n>\n=\n<pattern for output line 1>\n<pattern for output line 2>\n ...\n<pattern for output line m>\n<blank line>\n.DE\nPattern matching uses literal string comparison, with these exceptions:\n``%%'' matches the ``%'' character,\nand ``%'' followed by a digit matches everything\nup to the next occurrence of the next pattern character,\nthough all occurrences of %\\fIn\\fP must denote the same string.\nFor example, the pattern ``%1=%1.'' matches exactly those strings\nthat begin with a string X, followed by a ``='' (the first),\nfollowed by a second occurrence of X, followed by a period.\nIn this way, the input/output pattern\n.DS\nmov $%1,r%2\nmov *r%2,r%2\n=\nmov %1,r%2\n.DE\ncommands \\fIcopt\\fP to replace runs like\n.DS\nmov $_a,r3\nmov *r3,r3\n.DE\nwith\n.DS\nmov _a,r3\n.DE\nNote that a tab or newline can terminate a %\\fIn\\fP variable.\n.LP\nIn the input pattern, you can use \\fIregular exporessions\\fP to\nmatch input patterns and generate values for variables. The syntax\nis\n.DS\n%\"\\fI<expr>\\fP\"\\fI<n>\\fP\n.DE\nwhere \\fI<expr>\\fP is the (extended) POSIX regular expression and\n\\fI<n>\\fP \\fIoptional\\fP variable ident (as above). If the expression\nmatches input, the matched pattern will be assigned to the variable.\nIf there is at least one subexpression in \\fI<expr>\\fP and a variable\nis specified, then the match of the \\fUfirst\\fP subexpression will be\ntaken. Prefix and suffix (if any) will be skipped.\nExample:\n.DS\n \\fIj%\".\"0 %\"(.),\"1%2\\fP  matches  \\fBjr c,l_label\\fP  and assignes\n '\\fIr\\fP' to %0, '\\fIc\\fP' to %1 and '\\fIl_label\\fP' to %2. It\n won't match  jr nc,l_label. This can be used to output\n inverted jumps:  \\fIj%0 n%1,%2\\fP  will gain  \\fIjr nc,l_label\\fP.\n.DE\n\\fBImportant\\fP: If setting a variable, you \\fImust\\fP use the \\fIlast\\fP\noccurance of the variable in the input pattern, because copt\nmatches input patterns in reverse order.\n.LP\nOccurances of %L, %M or %N in the output pattern will be substituted\nby unique integers to allow creation of up to 3 labels.\nFor example, the output pattern\n.DS\n\t\tsbc\thl,de\n\t\tjr\tc,_unique_%L\n\t\tjr\tz,_unique_%M\n\t\tinc\ta\n ._unique_%L\n\t\tinc\ta\n ._unique_%M\n.DE\ncould produce\n.DS\n\t\tsbc\thl,de\n\t\tjr\tc,_unique_1\n\t\tjr\tz,_unique_2\n\t\tinc\ta\n ._unique_1\n\t\tinc\ta\n ._unique_2\n.DE\n.LP\nIf the second part of a rule starts with the line \\fI%once\\fP,\nthis rule will be \"fired\" only once. Example:\n.DS\n\t---- rules ----           ---- source ----\n\t.%0                       .l_10\n\t\tj%\"r|p\"2\t%1        \tjp\tl_label\n\t=                         \t...\n\t%activate                 \tjr\tl_10\n\t.%0                       \t...\n\t\tj%2\t%1                .l_label\n\t=                         \t...\n\t%activate\n\t.%1                       ---- result ----\n\t=                         \t...\n\t%%once                    \tjp\tl_10\n\t.%0                       \t...\n\t.%1                       .l10\n\t%activate                 .l_label\n\t\tjr\t%0                \t...\n\t=\n\t\tjp\t%0\n.DE\n.LP\nIf the output pattern starts with \\fI%activate\\fP it has to contain a valid\nrule that will be \"activated\" upon first match. \\fIcopt\\fP first evaluates the\ncontained rule (i.e. replaces %\\fIn\\fP variables as usual) and then replaces\nthe current rule with the contained one. At the same time, a flag is set, that\nwill cause a new pass through the source after the current pass finishes.\nNested activations are allowed. Note that you have to duplicate all \\fI%\\fP\ncharacters with each nesting level.\n.LP\n Example rule       Source              Output\n ---------------    ------------------\t-----------------\n .%0                   jp  z,l_label       jp  z,l_other\n\t jp  %1            ...                 ...\n =                     ...                 ...           \n %activate         .l_label            .l_label          \n .%1                   jp  l_other         jp  l_other   \n =                     ...                 ...           \n %%activate                   ...                 ...           \n     jp%%%%0%0     .l_other            .l_other          \n =                     ...                 ...           \n     jp%%%%0%1   \n.LP\nYou can activate several rules at once, simply by appending further\nrules, separated by an '%activate' line.\n.LP\nBlank lines and lines starting with \\fI;;\\fP in the first column\nthat occure in front of a rule will be ignored. This allows to\ncomment the rule file and add some blank lines between them for\nbetter readability.\n\n;; this is a comment\n\n.LP\n\\fIcopt\\fP compares each run of input patterns\nwith the current input instruction and its predecessors.\nIf no match is found, it advances to the next input instruction and tries again.\nOtherwise, it replaces the input instructions\nwith the corresponding output patterns, pattern variables instantiated,\nand resumes its search with the \\fIfirst\\fP instruction of the replacement.\n\\fIcopt\\fP matches input patterns in reverse order \nto cascade optimizations without backing up.\n.SH BUGS\nErrors in optimization files are always possible.\n.SH SEE ALSO\nregex(7)\n.SH AUTHORS\n.TP\n.B \\^Christian W. Fraser 1984\ncopt version 1.00\n.TP\n.B \\^DG 1999\nAdded out of memory checking and ANSI prototyping\n.TP\n.B \\^Zrin Ziborski 2002\nAdded comment lines, %L-%N variables, %activate,\nregexp capability and %check\n\n"
  },
  {
    "path": "64_6809_Target/expr.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include \"expr.h\"\n#include \"gen.h\"\n#include \"misc.h\"\n#include \"parse.h\"\n#include \"sym.h\"\n#include \"target.h\"\n#include \"tree.h\"\n#include \"types.h\"\n\n// Parsing of expressions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// expression_list: <null>\n//        | expression\n//        | expression ',' expression_list\n//        ;\n\n// Parse a list of zero or more comma-separated expressions and\n// return an AST composed of A_GLUE nodes with the left-hand child\n// being the sub-tree of previous expressions (or NULL) and the right-hand\n// child being the next expression. Each A_GLUE node will have size field\n// set to the number of expressions in the tree at this point. If no\n// expressions are parsed, NULL is returned\nstruct ASTnode *expression_list(int endtoken) {\n  struct ASTnode *tree = NULL;\n  struct ASTnode *child = NULL;\n  int exprcount = 0;\n\n  // Loop until the end token\n  while (Token.token != endtoken) {\n\n    // Parse the next expression and increment the expression count\n    child = binexpr(0);\n    exprcount++;\n\n    // Build an A_GLUE AST node with the previous tree as the left child\n    // and the new expression as the right child. Store the expression count.\n    tree =\n      mkastnode(A_GLUE, P_NONE, NULL, tree, NULL, child, NULL, exprcount);\n\n    // Stop when we reach the end token\n    if (Token.token == endtoken)\n      break;\n\n    // Must have a ',' at this point\n    match(T_COMMA, \",\");\n  }\n\n  // Return the tree of expressions\n  return (tree);\n}\n\n// Recursively check a function call's arguments\n// against the function's parameters. We take the\n// an AST subtree with the arguments and the pointer\n// to the function's first parameter or local. We walk\n// the AST tree and return a pointer to the next\n// parameter to process.\nstruct symtable *check_arg_vs_param(struct ASTnode *tree,\n\t\t\t\t    struct symtable *param,\n\t\t\t\t    struct symtable *funcptr) {\n\n  // No tree but there's a parameter, not enough args.\n  // Otherwise, nothing to do.\n  if (tree == NULL) {\n    if (param != NULL && param->class==V_PARAM)\n      fatal(\"Not enough arguments in function call A\");\n    return (NULL);\n  }\n\n  // If there's a left AST child, recurse to process it\n  if (tree->left != NULL)\n    param = check_arg_vs_param(tree->left, param, funcptr);\n\n  // We've bottomed out of the recursion\n  if (tree->right == NULL)\n    fatal(\"Not enough arguments in function call B\");\n\n  if (param == NULL) {\n    // If the function allows arbitrary number of arguments,\n    // we can process this argument. Otherwise it's an error.\n    if (funcptr->has_ellipsis) {\n\n      // If the tree's type is P_CHAR, widen it to P_INT.\n      // This is mainly for doing printf(\"%d\", 'x');\n      if (tree->right->type == P_CHAR) {\n\ttree->right= mkastunary(A_WIDEN, P_INT, NULL, tree->right, NULL, 0);\n\ttree->rightid= tree->right->nodeid;\n      }\n      return (NULL);\n    }\n    fatal(\"Too many arguments in function call\");\n  }\n\n  // Slightly dirty hack: change any INTLIT type to be the same\n  // type as the function's parameter before we evaluate it.\n  if (tree->right->op == A_INTLIT)\n    tree->right->type = param->type;\n\n  // Ensure the arg/param types are compatible.\n  // Widen the argument if necessary\n  tree->right = modify_type(tree->right, param->type, param->ctype, 0);\n  tree->rightid= tree->right->nodeid;\n  if (tree->right == NULL)\n    fatal(\"Incompatible argument type in function call\");\n\n  // Now return the next parameter for our caller to process.\n  // Return NULL when we hit the first local, as they come\n  // after all the parameters.\n  if (param->next != NULL && param->next->class==V_LOCAL) return(NULL);\n  return (param->next);\n}\n\n// Parse a function call and return its AST\nstatic struct ASTnode *funccall(void) {\n  struct ASTnode *tree;\n  struct symtable *funcptr;\n\n  // Check that the identifier has been defined as a function,\n  // then make a leaf node for it.\n  if ((funcptr = findSymbol(Text, S_NOTATYPE, 0)) == NULL || funcptr->stype != S_FUNCTION) {\n    fatals(\"Undeclared function\", Text);\n  }\n  // Get the '('\n  lparen();\n\n  // Parse the argument expression list\n  tree = expression_list(T_RPAREN);\n\n  // Check type of each argument against the function's prototype\n  check_arg_vs_param(tree, funcptr->member, funcptr);\n\n  // Build the function call AST node. Store the\n  // function's return type as this node's type.\n  // Also record the function's symbol-id\n  tree =\n    mkastunary(A_FUNCCALL, funcptr->type, funcptr->ctype, tree, funcptr, 0);\n\n  // Get the ')'\n  rparen();\n  return (tree);\n}\n\n// Parse the index into an array and return an AST tree for it\nstatic struct ASTnode *array_access(struct ASTnode *left) {\n  struct ASTnode *right;\n\n  // Check that the sub-tree is a pointer\n  if (!ptrtype(left->type))\n    fatal(\"Not an array or pointer\");\n\n  // Get the '['\n  scan(&Token);\n\n  // Parse the following expression\n  right = binexpr(0);\n\n  // Get the ']'\n  match(T_RBRACKET, \"]\");\n\n  // Ensure that this is of int type\n  if (!inttype(right->type))\n    fatal(\"Array index is not of integer type\");\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Scale the index by the size of the element's type\n  right = modify_type(right, left->type, left->ctype, A_ADD);\n\n  // Return an AST tree where the array's base has the offset added to it,\n  // and dereference the element. Still an lvalue at this point.\n  left =\n    mkastnode(A_ADD, left->type, left->ctype, left, NULL, right, NULL, 0);\n  left =\n    mkastunary(A_DEREF, value_at(left->type), left->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse the member reference of a struct or union\n// and return an AST tree for it. If withpointer is true,\n// the access is through a pointer to the member.\nstatic struct ASTnode *member_access(struct ASTnode *left, int withpointer) {\n  struct ASTnode *right;\n  struct symtable *typeptr;\n  struct symtable *m;\n\n  // Check that the left AST tree is a pointer to struct or union\n  if (withpointer && left->type != pointer_to(P_STRUCT)\n      && left->type != pointer_to(P_UNION))\n    fatal(\"Expression is not a pointer to a struct/union\");\n\n  // Or, check that the left AST tree is a struct or union.\n  // If so, change it from an A_IDENT to an A_ADDR so that\n  // we get the base address, not the value at this address.\n  if (!withpointer) {\n    if (left->type == P_STRUCT || left->type == P_UNION)\n      left->op = A_ADDR;\n    else\n      fatal(\"Expression is not a struct/union\");\n  }\n  // Get the details of the composite type\n  typeptr = left->ctype;\n\n  // Skip the '.' or '->' token and get the member's name\n  scan(&Token);\n  ident();\n\n  // Find the matching member's name in the type\n  // Die if we can't find it\n  for (m = typeptr->member; m != NULL; m = m->next)\n    if (!strcmp(m->name, Text))\n      break;\n  if (m == NULL)\n    fatals(\"No member found in struct/union: \", Text);\n\n  // Make the left tree an rvalue\n  left->rvalue = 1;\n\n  // Build an A_INTLIT node with the offset. Use the\n  // right int size that can be added to the address.\n  right = mkastleaf(A_INTLIT, cgaddrint(), NULL, NULL, m->st_posn);\n\n  // Add the member's offset to the base of the struct/union\n  // and dereference it. Still an lvalue at this point\n  left =\n    mkastnode(A_ADD, pointer_to(m->type), m->ctype, left, NULL, right, NULL,\n\t      0);\n  left = mkastunary(A_DEREF, m->type, m->ctype, left, NULL, 0);\n  return (left);\n}\n\n// Parse a parenthesised expression and\n// return an AST node representing it.\nstatic struct ASTnode *paren_expression(int ptp) {\n  struct ASTnode *n;\n  int type = 0;\n  struct symtable *ctype = NULL;\n\n  // Beginning of a parenthesised expression, skip the '('.\n  scan(&Token);\n\n  // If the token after is a type identifier, this is a cast expression\n  switch (Token.token) {\n  case T_IDENT:\n    // We have to see if the identifier matches a typedef.\n    // If not, treat it as an expression.\n    if (findtypedef(Text) == NULL) {\n      n = binexpr(0);\t\t// ptp is zero as expression inside ( )\n      break;\n    }\n  case T_VOID:\n  case T_CHAR:\n  case T_INT:\n  case T_LONG:\n  case T_STRUCT:\n  case T_UNION:\n  case T_ENUM:\n    // Get the type inside the parentheses\n    type = parse_cast(&ctype);\n\n    // Skip the closing ')' and then parse the following expression\n    rparen();\n\n  default:\n    n = binexpr(ptp);\t\t// Scan in the expression. We pass in ptp\n    // as the cast doesn't change the\n    // expression's precedence\n  }\n\n  // We now have at least an expression in n, and possibly a non-zero type\n  // in type if there was a cast. Skip the closing ')' if there was no cast.\n  if (type == 0)\n    rparen();\n  else\n    // Otherwise, make a unary AST node for the cast\n    n = mkastunary(A_CAST, type, ctype, n, NULL, 0);\n  return (n);\n}\n\n// Parse a primary factor and return an\n// AST node representing it.\nstatic struct ASTnode *primary(int ptp) {\n  struct ASTnode *n;\n  struct symtable *varptr;\n  int type = 0;\n  int size, class, totalsize, prevsize;\n  struct symtable *ctype;\n  char *litval, *litend;\n\n  switch (Token.token) {\n  case T_STATIC:\n  case T_EXTERN:\n    fatal(\"Compiler doesn't support static or extern local declarations\");\n  case T_SIZEOF:\n    // Skip the T_SIZEOF and ensure we have a left parenthesis\n    scan(&Token);\n    if (Token.token != T_LPAREN)\n      fatal(\"Left parenthesis expected after sizeof\");\n    scan(&Token);\n\n    // Get the type inside the parentheses\n    type = parse_stars(parse_type(&ctype, &class));\n\n    // Get the type's size\n    size = typesize(type, ctype);\n    rparen();\n\n    // Make a leaf node int literal with the size\n    return (mkastleaf(A_INTLIT, P_INT, NULL, NULL, size));\n\n  case T_CHARLIT:\n    // For an CHARLIT token, make a leaf AST node for it.\n    n = mkastleaf(A_INTLIT, P_CHAR, NULL, NULL, Token.intvalue);\n\n  case T_INTLIT:\n    // For an INTLIT token, make a leaf AST node for it.\n    n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, Token.intvalue);\n    break;\n\n  case T_STRLIT:\n    // For a STRLIT token, build the literal string and store in name\n    totalsize= strlen(Text);\n    litval= (char *)malloc(totalsize+1);\n    strcpy(litval, Text);\n\n    // For successive STRLIT tokens,\n    // append their contents to litval\n    while (1) {\n      scan(&Peektoken);\n      if (Peektoken.token != T_STRLIT)\n\tbreak;\n\n      // Increment the total string size\n      // while saving the previous size\n      size = strlen(Text);\n      prevsize= totalsize;\n      totalsize += size;\n\n      // Allocate new memory with this total size\n      litval= (char *)realloc(litval, totalsize+1);\n\n      // Find the current string's end\n      litend= litval + prevsize;\n\n      // and copy the new literal to the end\n      strcpy(litend, Text);\n\n      scan(&Token);\t\t// To skip it properly\n    }\n\n    // Now make a leaf AST node for it. id is the string's label.\n    n = mkastleaf(A_STRLIT, pointer_to(P_CHAR), NULL, NULL, 0);\n    n->name= litval;\n    break;\n\n  case T_IDENT:\n    // See if this identifier exists as a symbol. For arrays, set rvalue to 1.\n    if ((varptr = findSymbol(Text, S_NOTATYPE, 0)) == NULL) {\n      fatals(\"Unknown variable or function\", Text);\n    }\n\n    switch (varptr->stype) {\n    case S_ENUMVAL:\n      // If the identifier matches an enum value,\n      // return an A_INTLIT node with the value\n      n = mkastleaf(A_INTLIT, P_INT, NULL, NULL, varptr->st_posn);\n      break;\n    case S_VARIABLE:\n      n = mkastleaf(A_IDENT, varptr->type, varptr->ctype, varptr, 0);\n      break;\n    case S_ARRAY:\n      n = mkastleaf(A_ADDR, varptr->type, varptr->ctype, varptr, 0);\n      n->rvalue = 1;\n      break;\n    case S_FUNCTION:\n      // Function call, see if the next token is a left parenthesis\n      scan(&Token);\n      if (Token.token != T_LPAREN)\n\tfatals(\"Function name used without parentheses\", Text);\n      return (funccall());\n    default:\n      fatals(\"Identifier not a scalar or array variable\", Text);\n    }\n\n    break;\n\n  case T_LPAREN:\n    return (paren_expression(ptp));\n\n  default:\n    fatals(\"Expecting a primary expression, got token\",\n\tTstring[Token.token]);\n  }\n\n  // Scan in the next token and return the leaf node\n  scan(&Token);\n  return (n);\n}\n\n// Parse a postfix expression and return\n// an AST node representing it. The\n// identifier is already in Text.\nstatic struct ASTnode *postfix(int ptp) {\n  struct ASTnode *n;\n\n  // Get the primary expression\n  n = primary(ptp);\n\n  // Loop until there are no more postfix operators\n  while (1) {\n    switch (Token.token) {\n    case T_LBRACKET:\n      // An array reference\n      n = array_access(n);\n      break;\n\n    case T_DOT:\n      // Access into a struct or union\n      n = member_access(n, 0);\n      break;\n\n    case T_ARROW:\n      // Pointer access into a struct or union\n      n = member_access(n, 1);\n      break;\n\n    case T_INC:\n      // Post-increment: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot ++ on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTINC;\n      break;\n\n    case T_DEC:\n      // Post-decrement: skip over the token\n      if (n->rvalue == 1)\n\tfatal(\"Cannot -- on rvalue\");\n      scan(&Token);\n\n      // Can't do it twice\n      if (n->op == A_POSTINC || n->op == A_POSTDEC)\n\tfatal(\"Cannot ++ and/or -- more than once\");\n\n      // and change the AST operation\n      n->op = A_POSTDEC;\n      break;\n\n    default:\n      return (n);\n    }\n  }\n\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n\n// Convert a binary operator token into a binary AST operation.\n// We rely on a 1:1 mapping from token to AST operation\nstatic int binastop(int tokentype) {\n  if (tokentype > T_EOF && tokentype <= T_MOD)\n    return (tokentype);\n  fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (0);\t\t\t// Keep -Wall happy\n}\n\n// Return true if a token is right-associative,\n// false otherwise.\nstatic int rightassoc(int tokentype) {\n  if (tokentype >= T_ASSIGN && tokentype <= T_ASSLASH)\n    return (1);\n  return (0);\n}\n\n// Operator precedence for each token. Must\n// match up with the order of tokens in defs.h\nstatic int OpPrec[] = {\n  0, 10, 10,\t\t\t// T_EOF, T_ASSIGN, T_ASPLUS,\n  10, 10,\t\t\t// T_ASMINUS, T_ASSTAR,\n  10, 10,\t\t\t// T_ASSLASH, T_ASMOD,\n  15,\t\t\t\t// T_QUESTION,\n  20, 30,\t\t\t// T_LOGOR, T_LOGAND\n  40, 50, 60,\t\t\t// T_OR, T_XOR, T_AMPER \n  70, 70,\t\t\t// T_EQ, T_NE\n  80, 80, 80, 80,\t\t// T_LT, T_GT, T_LE, T_GE\n  90, 90,\t\t\t// T_LSHIFT, T_RSHIFT\n  100, 100,\t\t\t// T_PLUS, T_MINUS\n  110, 110, 110\t\t\t// T_STAR, T_SLASH, T_MOD\n};\n\n// Check that we have a binary operator and\n// return its precedence.\nstatic int op_precedence(int tokentype) {\n  int prec;\n  if (tokentype > T_MOD)\n    fatals(\"Token with no precedence in op_precedence:\", Tstring[tokentype]);\n  prec = OpPrec[tokentype];\n  if (prec == 0)\n    fatals(\"Syntax error, token\", Tstring[tokentype]);\n  return (prec);\n}\n\n// prefix_expression: postfix_expression\n//     | '*'  prefix_expression\n//     | '&'  prefix_expression\n//     | '-'  prefix_expression\n//     | '++' prefix_expression\n//     | '--' prefix_expression\n//     ;\n\n// Parse a prefix expression and return \n// a sub-tree representing it.\nstatic struct ASTnode *prefix(int ptp) {\n  struct ASTnode *tree = NULL;\n  switch (Token.token) {\n  case T_AMPER:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Ensure that it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"& operator must be followed by an identifier\");\n\n    // Prevent '&' being performed on an array\n    if (tree->sym->stype == S_ARRAY)\n      fatal(\"& operator cannot be performed on an array\");\n\n    // Now change the operator to A_ADDR and the type to\n    // a pointer to the original type. Mark the identifier\n    // as needing a real memory address\n    tree->op = A_ADDR;\n    tree->type = pointer_to(tree->type);\n    tree->sym->st_hasaddr = 1;\n    break;\n  case T_STAR:\n    // Get the next token and parse it\n    // recursively as a prefix expression.\n    // Make it an rvalue\n    scan(&Token);\n    tree = prefix(ptp);\n    tree->rvalue = 1;\n\n    // Ensure the tree's type is a pointer\n    if (!ptrtype(tree->type))\n      fatal(\"* operator must be followed by an expression of pointer type\");\n\n    // Prepend an A_DEREF operation to the tree\n    tree =\n      mkastunary(A_DEREF, value_at(tree->type), tree->ctype, tree, NULL, 0);\n    break;\n  case T_MINUS:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_NEGATE operation to the tree and\n    // make the child an rvalue. Because chars are unsigned,\n    // also widen this if needed to int so that it's signed\n    tree->rvalue = 1;\n    if (tree->type == P_CHAR)\n      tree->type = P_INT;\n    tree = mkastunary(A_NEGATE, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INVERT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_INVERT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_INVERT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_LOGNOT:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // Prepend a A_LOGNOT operation to the tree and\n    // make the child an rvalue.\n    tree->rvalue = 1;\n    tree = mkastunary(A_LOGNOT, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_INC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"++ operator must be followed by an identifier\");\n\n    // Prepend an A_PREINC operation to the tree\n    tree = mkastunary(A_PREINC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  case T_DEC:\n    // Get the next token and parse it\n    // recursively as a prefix expression\n    scan(&Token);\n    tree = prefix(ptp);\n\n    // For now, ensure it's an identifier\n    if (tree->op != A_IDENT)\n      fatal(\"-- operator must be followed by an identifier\");\n\n    // Prepend an A_PREDEC operation to the tree\n    tree = mkastunary(A_PREDEC, tree->type, tree->ctype, tree, NULL, 0);\n    break;\n  default:\n    tree = postfix(ptp);\n  }\n  return (tree);\n}\n\n// Return an AST tree whose root is a binary operator.\n// Parameter ptp is the previous token's precedence.\nstruct ASTnode *binexpr(int ptp) {\n  struct ASTnode *left, *right;\n  struct ASTnode *ltemp, *rtemp;\n  int ASTop;\n  int tokentype;\n\n  // Get the tree on the left.\n  // Fetch the next token at the same time.\n  left = prefix(ptp);\n\n  // If we hit one of several terminating tokens, return just the left node\n  tokentype = Token.token;\n  if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n      tokentype == T_RBRACKET || tokentype == T_COMMA ||\n      tokentype == T_COLON || tokentype == T_RBRACE) {\n    left->rvalue = 1;\n    return (left);\n  }\n  // While the precedence of this token is more than that of the\n  // previous token precedence, or it's right associative and\n  // equal to the previous token's precedence\n  while ((op_precedence(tokentype) > ptp) ||\n\t (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {\n    // Fetch in the next integer literal\n    scan(&Token);\n\n    // Recursively call binexpr() with the\n    // precedence of our token to build a sub-tree\n    right = binexpr(OpPrec[tokentype]);\n\n    // Determine the operation to be performed on the sub-trees\n    ASTop = binastop(tokentype);\n\n    switch (ASTop) {\n    case A_TERNARY:\n      // Ensure we have a ':' token, scan in the expression after it\n      match(T_COLON, \":\");\n      ltemp = binexpr(0);\n\n      // Force the ternary condition to be boolean if\n      // it wasn't a boolean operation\n      if (left->op != A_LOGOR && left->op != A_LOGAND &&\n\t\t\t\t(left->op < A_EQ || left->op > A_GE))\n        left = mkastunary(A_TOBOOL, left->type, left->ctype, left, NULL, 0);\n\n      // Build and return the AST for this statement. Use the middle\n      // expression's type as the return type. We should also\n      // consider the third expression's type.\n      return (mkastnode\n\t      (A_TERNARY, right->type, right->ctype, left, right, ltemp,\n\t       NULL, 0));\n\n    case A_ASSIGN:\n      // Assignment\n      // Make the right tree into an rvalue\n      right->rvalue = 1;\n\n      // If the right tree is an A_INTLIT and the left type is P_CHAR,\n      // and the INTLIT is in the range 0 to 255, change the right's\n      // type to PCHAR to ensure we can do the assignment\n      if ((right->op == A_INTLIT) && (left->type == P_CHAR) &&\n\t  (right->a_intvalue >= 0) && (right->a_intvalue < 256))\n\tright->type = P_CHAR;\n\n      // Ensure the right's type matches the left\n      right = modify_type(right, left->type, left->ctype, 0);\n      if (right == NULL)\n\tfatal(\"Incompatible expression in assignment\");\n\n      // Make an assignment AST tree. However, switch\n      // left and right around, so that the right expression's \n      // code will be generated before the left expression\n      ltemp = left;\n      left = right;\n      right = ltemp;\n      break;\n\n    default:\n      // We are not doing a ternary or assignment, so both trees should\n      // be rvalues. Convert both trees into rvalue if they are lvalue trees\n      left->rvalue = 1;\n      right->rvalue = 1;\n\n      // If the right tree is an A_INTLIT and the left type is P_CHAR,\n      // and the INTLIT is in the range 0 to 255, change the right's\n      // type to PCHAR to ensure we can do the assignment\n      if ((right->op == A_INTLIT) && (left->type == P_CHAR) &&\n\t  (right->a_intvalue >= 0) && (right->a_intvalue < 256))\n\tright->type = P_CHAR;\n\n      // Ensure the two types are compatible by trying\n      // to modify each tree to match the other's type.\n      ltemp = modify_type(left, right->type, right->ctype, ASTop);\n      rtemp = modify_type(right, left->type, left->ctype, ASTop);\n      if (ltemp == NULL && rtemp == NULL)\n\tfatal(\"Incompatible types in binary expression\");\n      if (ltemp != NULL)\n\tleft = ltemp;\n      if (rtemp != NULL)\n\tright = rtemp;\n    }\n\n    // Join that sub-tree with ours. Convert the token\n    // into an AST operation at the same time.\n    left =\n      mkastnode(binastop(tokentype), left->type, left->ctype, left, NULL,\n\t\tright, NULL, 0);\n\n    // Some operators produce an int result regardless of their operands\n    switch (binastop(tokentype)) {\n    case A_LOGOR:\n    case A_LOGAND:\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      left->type = P_INT;\n    }\n\n    // Update the details of the current token.\n    // If we hit a terminating token, return just the left node\n    tokentype = Token.token;\n    if (tokentype == T_SEMI || tokentype == T_RPAREN ||\n\ttokentype == T_RBRACKET || tokentype == T_COMMA ||\n\ttokentype == T_COLON || tokentype == T_RBRACE) {\n      left->rvalue = 1;\n      return (left);\n    }\n  }\n\n  // Return the tree we have when the precedence\n  // is the same or lower\n  left->rvalue = 1;\n  return (left);\n}\n"
  },
  {
    "path": "64_6809_Target/expr.h",
    "content": "/* expr.c */\nstruct ASTnode *expression_list(int endtoken);\nstruct symtable *check_arg_vs_param(struct ASTnode *tree, struct symtable *param, struct symtable *funcptr);\nstruct ASTnode *binexpr(int ptp);\n"
  },
  {
    "path": "64_6809_Target/gen.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"cg.h\"\n#include \"decl.h\"\n#include \"gen.h\"\n#include \"misc.h\"\n#include \"target.h\"\n#include \"tree.h\"\n#include \"types.h\"\n\n// Generic code generator\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel, int loopendlabel,\n\t   int parentASTop);\n\n// Generate and return a new label number\nstatic int labelid = 1;\nint genlabel(void) {\n  return (labelid++);\n}\n\nvoid genfreeregs(int keepreg) {\n  cgfreeallregs(keepreg);\n}\n\nstatic void update_line(struct ASTnode *n) {\n  // Output the line into the assembly if we've\n  // changed the line number in the AST node\n  if (n->linenum != 0 && Line != n->linenum) {\n    Line = n->linenum;\n    cglinenum(Line);\n  }\n}\n\n// Generate the code for an IF statement\n// and an optional ELSE clause.\nstatic int genIF(struct ASTnode *n, struct ASTnode *nleft,\n\t\t struct ASTnode *nmid, struct ASTnode *nright,\n\t\t int looptoplabel, int loopendlabel) {\n  int Lfalse, Lend;\n\n  // Generate two labels: one for the\n  // false compound statement, and one\n  // for the end of the overall IF statement.\n  // When there is no ELSE clause, Lfalse _is_\n  // the ending label!\n  Lfalse = genlabel();\n  if (nright)\n    Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(nleft, Lfalse, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the true compound statement\n  genAST(nmid, NOLABEL, looptoplabel, loopendlabel, n->op);\n  genfreeregs(NOREG);\n\n  // If there is an optional ELSE clause,\n  // generate the jump to skip to the end\n  if (nright)\n    cgjump(Lend);\n\n  // Now the false label\n  cglabel(Lfalse);\n\n  // Optional ELSE clause: generate the\n  // false compound statement and the\n  // end label\n  if (nright) {\n    genAST(nright, NOLABEL, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    cglabel(Lend);\n  }\n\n  return (NOREG);\n}\n\n// Generate the code for a WHILE statement\nstatic int genWHILE(struct ASTnode *n, struct ASTnode *nleft,\n\t\t    struct ASTnode *nright) {\n  int Lstart, Lend;\n\n  // Generate the start and end labels\n  // and output the start label\n  Lstart = genlabel();\n  Lend = genlabel();\n  cglabel(Lstart);\n\n  // Generate the condition code followed\n  // by a jump to the end label.\n  genAST(nleft, Lend, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Generate the compound statement for the body\n  genAST(nright, NOLABEL, Lstart, Lend, n->op);\n  genfreeregs(NOREG);\n\n  // Finally output the jump back to the condition,\n  // and the end label\n  cgjump(Lstart);\n  cglabel(Lend);\n  return (NOREG);\n}\n\n// Generate the code for a SWITCH statement\nstatic int genSWITCH(struct ASTnode *n, int looptoplabel) {\n  int *caseval, *caselabel;\n  int Ljumptop, Lend;\n  int i, reg, defaultlabel = 0, casecount = 0;\n  int rightid;\n  struct ASTnode *nleft;\n  struct ASTnode *nright;\n  struct ASTnode *c, *cleft;\n\n  // Load in the sub-nodes\n  nleft=loadASTnode(n->leftid,0);\n  nright=loadASTnode(n->rightid,0);\n\n  // Create arrays for the case values and associated labels.\n  // Ensure that we have at least one position in each array.\n  caseval = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n  caselabel = (int *) malloc((n->a_intvalue + 1) * sizeof(int));\n\n  // Generate labels for the top of the jump table, and the\n  // end of the switch statement. Set a default label for\n  // the end of the switch, in case we don't have a default.\n  Ljumptop = genlabel();\n  Lend = genlabel();\n  defaultlabel = Lend;\n\n  // Build the case value and label arrays\n  for (i = 0, c = nright; c != NULL;) {\n    // Get a label for this case. Store it\n    // and the case value in the arrays.\n    // Record if it is the default case.\n    caselabel[i] = genlabel();\n    caseval[i] = c->a_intvalue;\n    if (c->op == A_DEFAULT)\n      defaultlabel = caselabel[i];\n    else\n      casecount++;\n\n    i++;\n    rightid= c->rightid;\n    // Don't free c if it is nright,\n    // as genAST() will do this\n    if (c!=nright) freeASTnode(c);\n    c = loadASTnode(rightid,0);\n  }\n\n  // Output the code to calculate the switch condition\n  reg = genAST(nleft, NOLABEL, NOLABEL, NOLABEL, 0);\n  cgjump(Ljumptop);\n  genfreeregs(reg);\n\n  // Output the switch code or switch table\n  cgswitch(reg, casecount, Ljumptop, caselabel, caseval, defaultlabel);\n\n  // Generate the code for each case\n  for (i = 0, c = nright; c != NULL; ) {\n    // Generate the case code. Pass in the end label for the breaks.\n    // If case has no body, we will fall into the following body.\n    cglabel(caselabel[i]);\n    if (c->leftid) {\n      // Looptoplabel is here so we can 'continue', e.g.\n      // while (...) {\n      //   switch(...) {\n      //     case ...: ...\n      //               continue;\n      //   }\n      // }\n      cleft= loadASTnode(c->leftid,0);\n      genAST(cleft, NOLABEL, looptoplabel, Lend, 0);\n      freeASTnode(cleft);\n    }\n    genfreeregs(NOREG);\n\n    i++;\n    rightid= c->rightid;\n    freeASTnode(c);\n    c= loadASTnode(rightid,0);\n  }\n\n  // Output the end label\n  cglabel(Lend);\n  free(caseval);\n  free(caselabel);\n  freeASTnode(nleft);\n  return (NOREG);\n}\n\n// Generate the code for an A_LOGOR operation.\n// If the parent AST node is an A_IF, A_WHILE, A_TERNARY\n// or A_LOGAND, jump to the label if false.\n// If A_LOGOR, jump to the label if true.\n// Otherwise set a register to 1 or 0 and return it.\nstatic int gen_logor(struct ASTnode *n,\n\t\t     struct ASTnode *nleft, struct ASTnode *nright,\n\t\t     int parentASTop, int label) {\n  int Ltrue, Lfalse, Lend;\n  int reg;\n  int type;\n  int makebool = 0;\n\n  // Generate labels\n  if (parentASTop == A_LOGOR) {\n    Ltrue = label;\n    Lfalse = genlabel();\n  } else {\n    Ltrue = genlabel();\n    Lfalse = label;\n  }\n  Lend = genlabel();\n\n  // Mark if we need to generate a boolean value\n  if (parentASTop != A_IF && parentASTop != A_WHILE &&\n      parentASTop != A_TERNARY && parentASTop != A_LOGAND &&\n      parentASTop != A_LOGOR) {\n    makebool = 1;\n    Ltrue = genlabel();\n    Lfalse = genlabel();\n  }\n\n  // Generate the code for the left expression.\n  // The genAST() could do the jump and return NOREG.\n  // But if we get a register back, do our own jump.\n  reg = genAST(nleft, Ltrue, NOLABEL, NOLABEL, A_LOGOR);\n  if (reg != NOREG) {\n    type = nleft->type;\n    cgboolean(reg, A_LOGOR, Ltrue, type);\n    genfreeregs(NOREG);\n  }\n\n  // Generate the code for the right expression\n  // with the same logic as for the left expression.\n  reg = genAST(nright, Ltrue, NOLABEL, NOLABEL, A_LOGOR);\n  if (reg != NOREG) {\n    type = nright->type;\n    cgboolean(reg, A_LOGOR, Ltrue, type);\n    genfreeregs(reg);\n  }\n\n  // The result is false.\n  // If there is no need to make a boolean, stop now\n  if (makebool == 0) {\n    // Jump to the false label if it was provided\n    if (label == Lfalse) {\n      cgjump(Lfalse);\n      cglabel(Ltrue);\n    }\n    return (NOREG);\n  }\n\n  // We do need to make a boolean and we didn't jump\n  type = n->type;\n  cglabel(Lfalse);\n  reg = cgloadboolean(reg, 0, type);\n  cgjump(Lend);\n  cglabel(Ltrue);\n  reg = cgloadboolean(reg, 1, type);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Generate the code for an A_LOGAND operation.\n// If the parent AST node is an A_IF, A_WHILE, A_TERNARY\n// or A_LOGAND, jump to the label if false.\n// If A_LOGOR, jump to the label if true.\n// Otherwise set a register to 1 or 0 and return it.\nstatic int gen_logand(struct ASTnode *n,\n\t\t      struct ASTnode *nleft, struct ASTnode *nright,\n\t\t      int parentASTop, int label) {\n  int Ltrue, Lfalse, Lend;\n  int reg;\n  int type;\n  int makebool = 0;\n\n  // Generate labels\n  if (parentASTop == A_LOGOR) {\n    Ltrue = label;\n    Lfalse = genlabel();\n  } else {\n    Ltrue = genlabel();\n    Lfalse = label;\n  }\n\n  Lend = genlabel();\n\n  // Mark if we need to generate a boolean value\n  if (parentASTop != A_IF && parentASTop != A_WHILE &&\n      parentASTop != A_TERNARY && parentASTop != A_LOGAND &&\n      parentASTop != A_LOGOR) {\n    makebool = 1;\n    Ltrue = genlabel();\n    Lfalse = genlabel();\n  }\n\n  // Generate the code for the left expression.\n  // The genAST() could do the jump and return NOREG.\n  // But if we get a register back, do our own jump.\n  reg = genAST(nleft, Lfalse, NOLABEL, NOLABEL, A_LOGAND);\n  if (reg != NOREG) {\n    type = nleft->type;\n    cgboolean(reg, A_LOGAND, Lfalse, type);\n    genfreeregs(NOREG);\n  }\n\n  // Generate the code for the right expression\n  // with the same logic as for the left expression.\n  reg = genAST(nright, Lfalse, NOLABEL, NOLABEL, A_LOGAND);\n  if (reg != NOREG) {\n    type = nright->type;\n    cgboolean(reg, A_LOGAND, Lfalse, type);\n    genfreeregs(reg);\n  }\n\n  // The result is true.\n  // If there is no need to make a boolean, stop now\n  if (makebool == 0) {\n    // Jump to the label if we were given it\n    if (label == Ltrue) {\n      cgjump(Ltrue);\n      cglabel(Lfalse);\n    }\n    return (NOREG);\n  }\n\n  // We do need to make a boolean and we didn't jump\n  type = n->type;\n  cglabel(Ltrue);\n  reg = cgloadboolean(reg, 1, type);\n  cgjump(Lend);\n  cglabel(Lfalse);\n  reg = cgloadboolean(reg, 0, type);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Generate the code to calculate the arguments of a\n// function call, then call the function with these\n// arguments. Return the register that holds\n// the function's return value.\nstatic int gen_funccall(struct ASTnode *n) {\n  struct ASTnode *gluetree;\n  int i = 0, numargs = 0;\n  int reg;\n  int leftid;\n  int *arglist = NULL;\n  int *typelist = NULL;\n  struct ASTnode *nleft;\n  struct ASTnode *glueright;\n\n  // Load in the sub-nodes\n  nleft=loadASTnode(n->leftid,0);\n\n  // Determine the actual number of arguments\n  // Allocate memory to hold the list of argument temporaries.\n  // We need to walk the list of arguments to determine the size\n  // XXX We need to free here\n  for (i = 0, gluetree = nleft; gluetree != NULL; ) {\n    numargs++;\n    i++;\n    leftid= gluetree->leftid;\n    // Don't free gluetree if it is nleft,\n    // as genAST() will do this for us\n    if (gluetree != nleft) freeASTnode(gluetree);\n    gluetree = loadASTnode(leftid,0);\n  }\n\n  if (i != 0) {\n    arglist = (int *) malloc(i * sizeof(int));\n    if (arglist == NULL)\n      fatal(\"malloc failed in gen_funccall\");\n    typelist = (int *) malloc(i * sizeof(int));\n    if (typelist == NULL)\n      fatal(\"malloc failed in gen_funccall\");\n  }\n\n  // If there is a list of arguments, walk this list\n  // from the last argument (right-hand child) to the first.\n  // Also cache the type of each expression\n  for (i = 0, gluetree = nleft; gluetree != NULL;\n\t\t\t\tgluetree = loadASTnode(leftid,0)) {\n    // Calculate the expression's value\n    glueright= loadASTnode(gluetree->rightid,0);\n    arglist[i] =\n      genAST(glueright, NOLABEL, NOLABEL, NOLABEL, gluetree->op);\n    typelist[i++] = glueright->type;\n    freeASTnode(glueright);\n    leftid= gluetree->leftid;\n    freeASTnode(gluetree);\n  }\n\n  // Call the function and return its result\n  reg= cgcall(n->sym, numargs, arglist, typelist);\n  free(arglist);\n  free(typelist);\n  return(reg);\n}\n\n// Generate code for a ternary expression\nstatic int gen_ternary(struct ASTnode *n, struct ASTnode *nleft,\n\t\t       struct ASTnode *nmid, struct ASTnode *nright) {\n  int Lfalse, Lend;\n  int reg, expreg;\n\n  // Load in the sub-nodes\n  nleft=loadASTnode(n->leftid,0);\n  nmid=loadASTnode(n->midid,0);\n  nright=loadASTnode(n->rightid,0);\n\n  // Generate two labels: one for the\n  // false expression, and one for the\n  // end of the overall expression\n  Lfalse = genlabel();\n  Lend = genlabel();\n\n  // Generate the condition code followed\n  // by a jump to the false label.\n  genAST(nleft, Lfalse, NOLABEL, NOLABEL, n->op);\n  // genfreeregs(NOREG);\n\n  // Get a register to hold the result of the two expressions\n  reg = cgallocreg(nleft->type);\n\n  // Generate the true expression and the false label.\n  // Move the expression result into the known register.\n  expreg = genAST(nmid, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg, nmid->type);\n  cgfreereg(expreg);\n  cgjump(Lend);\n  cglabel(Lfalse);\n\n  // Generate the false expression and the end label.\n  // Move the expression result into the known register.\n  expreg = genAST(nright, NOLABEL, NOLABEL, NOLABEL, n->op);\n  cgmove(expreg, reg, nright->type);\n  cgfreereg(expreg);\n  cglabel(Lend);\n  return (reg);\n}\n\n// Given an AST, an optional label, and the AST op\n// of the parent, generate assembly code recursively.\n// Return the register id with the tree's final value.\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel,\n\t   int loopendlabel, int parentASTop) {\n  int leftreg = NOREG, rightreg = NOREG;\n  int type = P_VOID;\n  int id;\n  int special = 0;\n  struct ASTnode *nleft, *nmid, *nright;\n\n  // Empty tree, do nothing\n  if (n == NULL)\n    return (NOREG);\n\n  // Load in the sub-nodes\n  nleft=loadASTnode(n->leftid,0);\n  nmid=loadASTnode(n->midid,0);\n  nright=loadASTnode(n->rightid,0);\n\n  // Update the line number in the output\n  update_line(n);\n\n  // We have some specific AST node handling at the top\n  // so that we don't evaluate the child sub-trees immediately\n  switch (n->op) {\n  case A_IF:\n    special = 1;\n    leftreg = genIF(n, nleft, nmid, nright, looptoplabel, loopendlabel);\n    break;\n  case A_WHILE:\n    special = 1;\n    leftreg = genWHILE(n, nleft, nright);\n    break;\n  case A_SWITCH:\n    special = 1;\n    leftreg = genSWITCH(n, looptoplabel);\n    break;\n  case A_FUNCCALL:\n    special = 1;\n    leftreg = gen_funccall(n);\n    break;\n  case A_TERNARY:\n    special = 1;\n    leftreg = gen_ternary(n, nleft, nmid, nright);\n    break;\n  case A_LOGOR:\n    special = 1;\n    leftreg = gen_logor(n, nleft, nright, parentASTop, iflabel);\n    break;\n  case A_LOGAND:\n    special = 1;\n    leftreg = gen_logand(n, nleft, nright, parentASTop, iflabel);\n    break;\n  case A_GLUE:\n    // Do each child statement, and free the\n    // registers after each child\n    special = 1;\n    if (nleft != NULL)\n      genAST(nleft, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    if (nright != NULL)\n      genAST(nright, iflabel, looptoplabel, loopendlabel, n->op);\n    genfreeregs(NOREG);\n    leftreg = NOREG;\n    break;\n  case A_FUNCTION:\n    // Generate the function's preamble before the code\n    // in the child sub-tree. Ugly: use function's name\n    // as the Infilename for fatal messages.\n    special = 1;\n    Infilename = n->sym->name;\n    cgfuncpreamble(n->sym);\n    genAST(nleft, NOLABEL, NOLABEL, NOLABEL, n->op);\n    cgfuncpostamble(n->sym);\n    leftreg = NOREG;\n  }\n\n  if (!special) {\n\n    // General AST node handling below\n\n    // Get the left and right sub-tree values\n    if (nleft) {\n      type = nleft->type;\n      leftreg = genAST(nleft, NOLABEL, looptoplabel, loopendlabel, n->op);\n    }\n    if (nright) {\n      type = nright->type;\n      rightreg = genAST(nright, NOLABEL, looptoplabel, loopendlabel, n->op);\n    }\n\n    switch (n->op) {\n    case A_ADD:\n      leftreg = cgadd(leftreg, rightreg, type);\n      break;\n    case A_SUBTRACT:\n      leftreg = cgsub(leftreg, rightreg, type);\n      break;\n    case A_MULTIPLY:\n      leftreg = cgmul(leftreg, rightreg, type);\n      break;\n    case A_DIVIDE:\n      leftreg = cgdiv(leftreg, rightreg, type);\n      break;\n    case A_MOD:\n      leftreg = cgmod(leftreg, rightreg, type);\n      break;\n    case A_AND:\n      leftreg = cgand(leftreg, rightreg, type);\n      break;\n    case A_OR:\n      leftreg = cgor(leftreg, rightreg, type);\n      break;\n    case A_XOR:\n      leftreg = cgxor(leftreg, rightreg, type);\n      break;\n    case A_LSHIFT:\n      leftreg = cgshl(leftreg, rightreg, type);\n      break;\n    case A_RSHIFT:\n      leftreg = cgshr(leftreg, rightreg, type);\n      break;\n    case A_EQ:\n    case A_NE:\n    case A_LT:\n    case A_GT:\n    case A_LE:\n    case A_GE:\n      // If the parent AST node is an A_IF, A_WHILE, A_TERNARY,\n      // A_LOGAND, generate a compare followed by a jump if the\n      // comparison is false. If A_LOGOR, jump if true. Otherwise,\n      // compare registers and set one to 1 or 0 based on the comparison.\n      if (parentASTop == A_IF || parentASTop == A_WHILE ||\n\t  parentASTop == A_TERNARY || parentASTop == A_LOGAND ||\n\t  parentASTop == A_LOGOR) {\n\tleftreg = cgcompare_and_jump\n\t  (n->op, parentASTop, leftreg, rightreg, iflabel, nleft->type);\n      } else {\n\tleftreg = cgcompare_and_set(n->op, leftreg, rightreg, nleft->type);\n      }\n      break;\n    case A_INTLIT:\n      leftreg = cgloadint(n->a_intvalue, n->type);\n      break;\n    case A_STRLIT:\n      // Output the actual literal\n      id = genglobstr(n->name);\n      leftreg = cgloadglobstr(id);\n      break;\n    case A_IDENT:\n      // Load our value if we are an rvalue\n      // or we are being dereferenced\n      if (n->rvalue || parentASTop == A_DEREF) {\n\tleftreg = cgloadvar(n->sym, n->op);\n      } else\n\tleftreg = NOREG;\n      break;\n    case A_ASPLUS:\n    case A_ASMINUS:\n    case A_ASSTAR:\n    case A_ASSLASH:\n    case A_ASMOD:\n    case A_ASSIGN:\n\n      // For the '+=' and friends operators, generate suitable code\n      // and get the register with the result. Then take the left child,\n      // make it the right child so that we can fall into the assignment code.\n      switch (n->op) {\n      case A_ASPLUS:\n\tleftreg = cgadd(leftreg, rightreg, type);\n\tnright = nleft;\n\tbreak;\n      case A_ASMINUS:\n\tleftreg = cgsub(leftreg, rightreg, type);\n\tnright = nleft;\n\tbreak;\n      case A_ASSTAR:\n\tleftreg = cgmul(leftreg, rightreg, type);\n\tnright = nleft;\n\tbreak;\n      case A_ASSLASH:\n\tleftreg = cgdiv(leftreg, rightreg, type);\n\tnright = nleft;\n\tbreak;\n      case A_ASMOD:\n\tleftreg = cgmod(leftreg, rightreg, type);\n\tnright = nleft;\n\tbreak;\n      }\n\n      // Now into the assignment code\n      // Are we assigning to an identifier or through a pointer?\n      switch (nright->op) {\n      case A_IDENT:\n\tif (nright->sym->class == V_GLOBAL ||\n\t    nright->sym->class == V_EXTERN ||\n\t    nright->sym->class == V_STATIC) {\n\t  leftreg = cgstorglob(leftreg, nright->sym);\n\t} else {\n\t  leftreg = cgstorlocal(leftreg, nright->sym);\n\t}\n\tbreak;\n      case A_DEREF:\n\tleftreg = cgstorderef(leftreg, rightreg, nright->type);\n\tbreak;\n      default:\n\tfatald(\"Can't A_ASSIGN in genAST(), op\", n->op);\n      }\n      break;\n    case A_WIDEN:\n      // Widen the child's type to the parent's type\n      leftreg = cgwiden(leftreg, nleft->type, n->type);\n      break;\n    case A_RETURN:\n      cgreturn(leftreg, Functionid);\n      leftreg = NOREG;\n      break;\n    case A_ADDR:\n      // If we have a symbol, get its address. Otherwise,\n      // the left register already has the address because\n      // it's a member access\n      if (n->sym != NULL)\n\tleftreg = cgaddress(n->sym);\n      break;\n#ifdef SPLITSWITCH\n      }\n\n      // I've broken the switch statement into two, so that\n      // the 6809 version of the compiler can parse this file\n      // without running out of room.\n    switch (n->op) {\n#endif\n    case A_DEREF:\n      // If we are an rvalue, dereference to get the value we point at,\n      // otherwise leave it for A_ASSIGN to store through the pointer\n      if (n->rvalue)\n\tleftreg = cgderef(leftreg, nleft->type);\n      break;\n    case A_SCALE:\n      // Small optimisation: use shift if the\n      // scale value is a known power of two\n      switch (n->a_size) {\n      case 2:\n\tleftreg = cgshlconst(leftreg, 1, type);\n\tbreak;\n      case 4:\n\tleftreg = cgshlconst(leftreg, 2, type);\n\tbreak;\n      case 8:\n\tleftreg = cgshlconst(leftreg, 3, type);\n\tbreak;\n      default:\n\t// Load a register with the size and\n\t// multiply the leftreg by this size\n\trightreg = cgloadint(n->a_size, P_INT);\n\tleftreg = cgmul(leftreg, rightreg, type);\n      }\n\n      // On some architectures the pointer type is\n      // different to the int type. Widen the result\n      // if we are scaling what will become an address offset\n      if (cgprimsize(n->type) > cgprimsize(type))\n\tleftreg = cgwiden(leftreg, type, n->type);\n\n      break;\n    case A_POSTINC:\n    case A_POSTDEC:\n      // Load and decrement the variable's value into a register\n      // and post increment/decrement it\n      leftreg = cgloadvar(n->sym, n->op);\n      break;\n    case A_PREINC:\n    case A_PREDEC:\n      // Load and decrement the variable's value into a register\n      // and pre increment/decrement it\n      leftreg = cgloadvar(nleft->sym, n->op);\n      break;\n    case A_NEGATE:\n      leftreg = cgnegate(leftreg, type);\n      break;\n    case A_INVERT:\n      leftreg = cginvert(leftreg, type);\n      break;\n    case A_LOGNOT:\n      leftreg = cglognot(leftreg, type);\n      break;\n    case A_TOBOOL:\n      // If the parent AST node is an IF, WHILE, TERNARY,\n      // LOGAND or LOGOR operation, generate a compare\n      // followed by a jump. Otherwise, set the register\n      // to 0 or 1 based on it's zeroeness or non-zeroeness\n      leftreg = cgboolean(leftreg, parentASTop, iflabel, type);\n      break;\n    case A_BREAK:\n      cgjump(loopendlabel);\n      leftreg = NOREG;\n      break;\n    case A_CONTINUE:\n      cgjump(looptoplabel);\n      leftreg = NOREG;\n      break;\n    case A_CAST:\n      leftreg = cgcast(leftreg, nleft->type, n->type);\n      break;\n#ifndef SPLITSWITCH\n    default:\n      fatald(\"Unknown AST operator\", n->op);\n#endif\n    }\n  }\t\t\t\t// End of if (!special)\n\n  // Free the AST sub trees before returning\n  // Sometimes n->right has been set to n->left\n  // e.g. by the +=, -= etc. operations.\n  if (nright != nleft)\n    freeASTnode(nright);\n  freeASTnode(nleft);\n  freeASTnode(nmid);\n  return (leftreg);\n}\n\nvoid genpreamble() {\n  cgpreamble();\n}\n\nvoid genpostamble() {\n  cgpostamble();\n}\n\nvoid genglobsym(struct symtable *node) {\n  cgglobsym(node);\n}\n\n// Generate a global string.\nint genglobstr(char *strvalue) {\n  int l = genlabel();\n  cglitseg();\n  cgglobstr(l, strvalue);\n  cgtextseg();\n  return (l);\n}\n"
  },
  {
    "path": "64_6809_Target/gen.h",
    "content": "/* gen.c */\nint genlabel(void);\nint genAST(struct ASTnode *n, int iflabel, int looptoplabel, int loopendlabel, int parentASTop);\nvoid genpreamble();\nvoid genpostamble();\nvoid genfreeregs(int keepreg);\nvoid genglobsym(struct symtable *node);\nint genglobstr(char *strvalue);\n"
  },
  {
    "path": "64_6809_Target/include/6809/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\nint toupper(int c);\nint tolower(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "64_6809_Target/include/6809/errno.h",
    "content": "#ifndef __ERRNO_H\n#define __ERRNO_H\n\n/*\n * Error codes\n */\n#define EPERM           1               /* Not owner */\n#define ENOENT          2               /* No such file or directory */\n#define ESRCH           3               /* No such process */\n#define EINTR           4               /* Interrupted System Call */\n#define EIO             5               /* I/O Error */\n#define ENXIO           6               /* No such device or address */\n#define E2BIG           7               /* Arg list too long */\n#define ENOEXEC         8               /* Exec format error */\n#define EBADF           9               /* Bad file number */\n#define ECHILD          10              /* No children */\n#define EAGAIN          11              /* No more processes */\n#define ENOMEM          12              /* Not enough core */\n#define EACCES          13              /* Permission denied */\n#define EFAULT          14              /* Bad address */\n#define ENOTBLK         15              /* Block device required */\n#define EBUSY           16              /* Mount device busy */\n#define EEXIST          17              /* File exists */\n#define EXDEV           18              /* Cross-device link */\n#define ENODEV          19              /* No such device */\n#define ENOTDIR         20              /* Not a directory */\n#define EISDIR          21              /* Is a directory */\n#define EINVAL          22              /* Invalid argument */\n#define ENFILE          23              /* File table overflow */\n#define EMFILE          24              /* Too many open files */\n#define ENOTTY          25              /* Not a typewriter */\n#define ETXTBSY         26              /* Text file busy */\n#define EFBIG           27              /* File too large */\n#define ENOSPC          28              /* No space left on device */\n#define ESPIPE          29              /* Illegal seek */\n#define EROFS           30              /* Read-only file system */\n#define EMLINK          31              /* Too many links */\n#define EPIPE           32              /* Broken pipe */\n\n/* math software */\n#define EDOM            33              /* Argument too large */\n#define ERANGE          34              /* Result too large */\n\n#define EWOULDBLOCK\tEAGAIN\t\t/* Operation would block */\n#define ENOLOCK\t\t35\t\t/* Lock table full */\n#define ENOTEMPTY\t36\t\t/* Directory is not empty */\n#define ENAMETOOLONG    37              /* File name too long */\n#define EAFNOSUPPORT\t38\t\t/* Address family not supported */\n#define EALREADY\t39\t\t/* Operation already in progress */\n#define EADDRINUSE\t40\t\t/* Address already in use */\n#define EADDRNOTAVAIL\t41\t\t/* Address not available */\n#define ENOSYS\t\t42\t\t/* No such system call */\n#define EPFNOSUPPORT\t43\t\t/* Protocol not supported */\n#define EOPNOTSUPP\t44\t\t/* Operation not supported on transport endpoint */\n#define ECONNRESET\t45\t\t/* Connection reset by peer */\n#define ENETDOWN\t46\t\t/* Network is down */\n#define EMSGSIZE\t47\t\t/* Message too long */\n\n#define ETIMEDOUT\t48\t\t/* Connection timed out */\n#define ECONNREFUSED\t49\t\t/* Connection refused */\n#define EHOSTUNREACH\t50\t\t/* No route to host */\n#define EHOSTDOWN\t51\t\t/* Host is down */\n#define\tENETUNREACH\t52\t\t/* Network is unreachable */\n#define ENOTCONN\t53\t\t/* Transport endpoint is not connected */\n#define EINPROGRESS\t54\t\t/* Operation now in progress */\n#define ESHUTDOWN\t55\t\t/* Cannot send after transport endpoint shutdown */\n#define EISCONN         56              /* Socket is already connected */\n#define EDESTADDRREQ    57              /* No destination address specified */\n#define ENOBUFS\t\t58\t\t/* No buffer space available */\n#define EPROTONOSUPPORT\t59\t\t/* Protocol not supported */\n#define __ERRORS\t56\n\nextern int sys_nerr;\nextern char *sys_errlist[];\nextern int errno;\n\n#endif\n\n"
  },
  {
    "path": "64_6809_Target/include/6809/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n#define O_CREAT\t256\n\nint open(char *pathname, int flags, ...);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "64_6809_Target/include/6809/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef int size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "64_6809_Target/include/6809/stdint.h",
    "content": "#ifndef __STDINT_H\n#define __STDINT_H\n\n/* C types */\ntypedef char  uint8_t;\ntypedef short int16_t;\ntypedef long  int32_t;\n\n#endif\n"
  },
  {
    "path": "64_6809_Target/include/6809/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n#ifndef EOF\n# define EOF (-1)\n#endif\n\n#define __MODE_ERR      0x200   /* Error status */\n\nstruct __stdio_file {\n  char   *bufpos;        /* the next byte to write to or read from */\n  char   *bufread;       /* the end of data returned by last read() */\n  char   *bufwrite;      /* highest address writable by macro */\n  char   *bufstart;      /* the start of the buffer */\n  char   *bufend;        /* the end of the buffer; ie the byte after\n                            the last malloc()ed byte */\n  int    fd;             /* the file descriptor associated with the stream */\n  int    mode;\n  char   unbuf   ;       /* The buffer for 'unbuffered' streams */\n  char   unbuf1  ;\n  char   unbuf2  ;\n  char   unbuf3  ;\n  char   unbuf4  ;\n  char   unbuf5  ;\n  char   unbuf6  ;\n  char   unbuf7  ;\n  struct __stdio_file * next;\n};\n\ntypedef struct __stdio_file FILE;\n\n#define ferror(fp)\t(((fp)->mode&__MODE_ERR) != 0)\n#define getc(stream)    fgetc(stream)\n\nFILE *__fopen(char *__path, int __fd, FILE * __stream, char *__mode);\n#define fopen(__file, __mode)         __fopen((__file), -1, (FILE*)0, (__mode))\n#define freopen(__file, __mode, __fp) __fopen((__file), -1, (__fp), (__mode))\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format, ...);\nint fprintf(FILE *stream, char *format, ...);\nint sprintf(char *str, char *format, ...);\nint snprintf(char *str, size_t size, char *format, ...);\nint fgetc(FILE *stream);\nint getc(FILE *stream);\nint getchar(void);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\nFILE *popen(char *command, char *type);\nint pclose(FILE *stream);\nchar *fgets(char *s, int size, FILE *stream);\nint rename(char *path, char *newpath);\nint fseek(FILE *stream, long offset, int whence);\nlong ftell(FILE *stream);\nFILE *tmpfile(void);\n\n#ifndef SEEK_SET\n#define SEEK_SET 0\n#define SEEK_CUR 1\n#define SEEK_END 2\n#endif\n\nextern FILE stdin[1];\nextern FILE stdout[1];\nextern FILE stderr[1];\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "64_6809_Target/include/6809/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\nint system(char *command);\nint abs(int j);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "64_6809_Target/include/6809/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\nint strcmp(char *s1, char *s2);\nint strncmp(char *s1, char *s2, size_t n);\nchar *strcpy(char *dst, char *src);\nchar *strerror(int errnum);\nint strlen(char *s);\nchar *strcat(char *dst, char *src);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "64_6809_Target/include/6809/sys/stat.h",
    "content": "#ifndef _SYS_STAT\n#define _SYS_STAT\nint mkdir(char *pathname, int mode);\n#endif\n"
  },
  {
    "path": "64_6809_Target/include/6809/sys/types.h",
    "content": "#ifndef _SYS_TYPES\n#define _SYS_TYPES\n#include <stdint.h>\n\ntypedef int32_t off_t;\n\n#endif\n"
  },
  {
    "path": "64_6809_Target/include/6809/sys/wait.h",
    "content": "#ifndef _SYS_WAIT.H\n#define _SYS_WAIT.H\n\nint waitpid(int pid, int * wstatus, int options);\n#define WEXITSTATUS(status)     (((status) & 0xff00) >> 8)\n#define WIFEXITED(status)       (((status) & 0xff) == 0)\n\n#endif\n"
  },
  {
    "path": "64_6809_Target/include/6809/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\nint fork(void);\nint execvp(char *file, char **argv);\nint getopt(int argc, char **argv, char *optstring);\nint close(int fd);\nint read(int fd, void *buf, int len);\nint write(int fd, void *buf, int len);\nint link(char *path, char *path2);\nint chdir(char *path);\nint fchdir(int fd);\nint rmdir(char *pathname);\nint access(char *pathname, int mode);\n\nextern char *optarg;\nextern int optind, opterr, optopt;\n\n#define F_OK\t0\t/* Test for existence.\t*/\n#define F_ULOCK\t0\n#define F_LOCK\t1\n#define F_TLOCK\t2\n#define F_TEST\t3\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "64_6809_Target/include/qbe/ctype.h",
    "content": "#ifndef _CTYPE_H_\n# define _CTYPE_H_\n\nint isalnum(int c);\nint isalpha(int c);\nint iscntrl(int c);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int c);\nint isprint(int c);\nint ispunct(int c);\nint isspace(int c);\nint isupper(int c);\nint isxdigit(int c);\nint isascii(int c);\nint isblank(int c);\n\nint toupper(int c);\nint tolower(int c);\n\n#endif\t// _CTYPE_H_\n"
  },
  {
    "path": "64_6809_Target/include/qbe/errno.h",
    "content": "#ifndef _ERRNO_H_\n# define _ERRNO_H_\n\nint * __errno_location(void);\n\n#define errno (* __errno_location())\n\n#endif // _ERRNO_H_\n"
  },
  {
    "path": "64_6809_Target/include/qbe/fcntl.h",
    "content": "#ifndef _FCNTL_H_\n# define _FCNTL_H_\n\n#define O_RDONLY 00\n#define O_WRONLY 01\n#define O_RDWR   02\n\nint open(char *pathname, int flags, ...);\n\n#endif // _FCNTL_H_\n"
  },
  {
    "path": "64_6809_Target/include/qbe/stddef.h",
    "content": "#ifndef _STDDEF_H_\n# define _STDDEF_H_\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\ntypedef long size_t;\n\n#endif\t//_STDDEF_H_\n\n"
  },
  {
    "path": "64_6809_Target/include/qbe/stdio.h",
    "content": "#ifndef _STDIO_H_\n# define _STDIO_H_\n\n#include <stddef.h>\n\n#ifndef NULL\n# define NULL (void *)0\n#endif\n\n#ifndef EOF\n# define EOF (-1)\n#endif\n\n// This FILE definition will do for now\ntypedef char * FILE;\n\nFILE *fopen(char *pathname, char *mode);\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\nsize_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);\nint fclose(FILE *stream);\nint printf(char *format, ...);\nint fprintf(FILE *stream, char *format, ...);\nint sprintf(char *str, char *format, ...);\nint snprintf(char *str, size_t size, char *format, ...);\nint fgetc(FILE *stream);\nint getc(FILE *stream);\nint getchar(void);\nint fputc(int c, FILE *stream);\nint fputs(char *s, FILE *stream);\nint putc(int c, FILE *stream);\nint putchar(int c);\nint puts(char *s);\nFILE *popen(char *command, char *type);\nint pclose(FILE *stream);\nint ferror(FILE *stream);\nFILE *freopen(char *pathname, char *mode, FILE *stream);\nchar *fgets(char *s, int size, FILE *stream);\nlong ftell(FILE *stream);\nint fseek(FILE *stream, long offset, int whence);\nFILE *tmpfile(void);\n\n#ifndef SEEK_SET\n#define SEEK_SET 0\n#define SEEK_CUR 1\n#define SEEK_END 2\n#endif\n\nextern FILE *stdin;\nextern FILE *stdout;\nextern FILE *stderr;\n\n#endif\t// _STDIO_H_\n"
  },
  {
    "path": "64_6809_Target/include/qbe/stdlib.h",
    "content": "#ifndef _STDLIB_H_\n# define _STDLIB_H_\n\nvoid exit(int status);\nvoid _Exit(int status);\n\nvoid *malloc(int size);\nvoid free(void *ptr);\nvoid *calloc(int nmemb, int size);\nvoid *realloc(void *ptr, int size);\nint system(char *command);\nint abs(int j);\n\n#endif\t// _STDLIB_H_\n"
  },
  {
    "path": "64_6809_Target/include/qbe/string.h",
    "content": "#ifndef _STRING_H_\n# define _STRING_H_\n\nchar *strdup(char *s);\nchar *strchr(char *s, int c);\nchar *strrchr(char *s, int c);\nint strcmp(char *s1, char *s2);\nint strncmp(char *s1, char *s2, size_t n);\nchar *strcpy(char *dst, char *src);\nchar *strerror(int errnum);\nint strlen(char *s);\nchar *strcat(char *dst, char *src);\n\n#endif\t// _STRING_H_\n"
  },
  {
    "path": "64_6809_Target/include/qbe/sys/wait.h",
    "content": "#ifndef _SYS_WAIT.H\n#define _SYS_WAIT.H\n\nint waitpid(int pid, int * wstatus, int options);\n\n#define\t__WEXITSTATUS(status)\t(((status) & 0xff00) >> 8)\n#define\t__WTERMSIG(status)\t((status) & 0x7f)\n#define\t__WSTOPSIG(status)\t__WEXITSTATUS(status)\n#define\t__WIFEXITED(status)\t(__WTERMSIG(status) == 0)\n#define WEXITSTATUS(status)\t__WEXITSTATUS (status)\n#define WTERMSIG(status)\t__WTERMSIG (status)\n#define WIFEXITED(status)\t__WIFEXITED (status)\n\n#endif\n"
  },
  {
    "path": "64_6809_Target/include/qbe/unistd.h",
    "content": "#ifndef _UNISTD_H_\n# define _UNISTD_H_\n\nvoid _exit(int status);\nint unlink(char *pathname);\nint fork(void);\nint execvp(char *file, char **argv);\nint getopt(int argc, char **argv, char *optstring);\nextern char *optarg;\nextern int optind, opterr, optopt;\n\n#endif\t// _UNISTD_H_\n"
  },
  {
    "path": "64_6809_Target/lib/6809/Makefile",
    "content": "crt0.o: crt0.s\n\tas6809 crt0.s\n"
  },
  {
    "path": "64_6809_Target/lib/6809/crt0.s",
    "content": "\t.dp\n\t.export R0\n\t.export R1\n\t.export R2\n\t.export R3\n\t.export R4\n\t.export R5\n\t.export R6\n\t.export R7\n\nR0:\t.word\t0\n\t.word\t0\nR1:\t.word\t0\n\t.word\t0\nR2:\t.word\t0\n\t.word\t0\nR3:\t.word\t0\n\t.word\t0\nR4:\t.word\t0\n\t.word\t0\nR5:\t.word\t0\n\t.word\t0\nR6:\t.word\t0\n\t.word\t0\nR7:\t.word\t0\n\t.word\t0\n\n\t\t.code\nstart:\n\t\t.word 0x80A8\n\t\t.byte 0x04\t\t\t; 6809\n\t\t.byte 0x00\t\t\t; 6309 not needed\n\t\t.byte >__code\t\t\t; page to load at\n\t\t.byte 0\t\t\t\t; no hints\n\t\t.word __code_size\t\t; text size info\n\t\t.word __data_size\t\t; data size info\n\t\t.word __bss_size\t\t; bss size info\n\t\t.byte 16\t\t\t; entry relative to start\n\t\t.word __end\t\t\t; to help the emulator :-)\n\t\t.byte 0\t\t\t\t; ZP not used on 6809\n\n\t\tjmp start2\n\n\t\t.code\n\nstart2:\n\t\tldd\t#0\n\t\tstd\t@zero\n\t\tldd\t#1\n\t\tstd\t@one\n\n\t\t; Set up _environ\n\t\tldd 4,s\n\t\tstd _environ\n\n\t\tjsr ___stdio_init_vars\n\t\tjsr\t_main\n\n\t\t; return and exit\n\t\tjsr _exit\n\n\t\t.data\n\t\t.export _environ\n_environ:\t.word 0\n"
  },
  {
    "path": "64_6809_Target/lib/6809/rules.6809",
    "content": "# No need to add 0 to D\n#1\n\taddd #0\n=\n====\n# No need to in/decrease S by 0\n#2\n\tleas -0,s\n=\n====\n#3\n\tleas 0,s\n=\n====\n# Avoid D reloads\n#4\n\tstd %1\n\tldd %1\n=\n\tstd %1\n====\n#5\n\tstd %1\n;\n\tldd %1\n=\n\tstd %1\n====\n#6\n\tstd %1\n;\n;\n\tldd %1\n=\n\tstd %1\n====\n# Avoid B reloads\n#7\n\tstb %1\n\tldb %1\n=\n\tstb %1\n====\n#8\n\tstb %1\n;\n\tldb %1\n=\n\tstb %1\n====\n#9\n\tstb %1\n;\n;\n\tldb %1\n=\n\tstb %1\n====\n# Avoid using a temporary\n#10\n\tstd R%1\n\tldd %2\n\taddd R%1\n=\n\taddd %2\n====\n# Use indexed addressing\n#11\n\tldx %1,s\n\tldd 0,x\n=\n\tldd [%1,s]\n====\n#12\n\tldx %1,s\n\tstd 0,x\n=\n\tstd [%1,s]\n====\n#13\n\tldx %1,s\n\tldb 0,x\n=\n\tldb [%1,s]\n====\n#14\n\tldx %1,s\n\tstb 0,x\n=\n\tstb [%1,s]\n====\n# Some more indexed addressing\n#15\n\tldx %1,s\n\tldd %2\n\tstd 0,x\n=\n\tldd %2\n\tstd [%1,s]\n====\n# Skip some D to X transfers\n#16\n\tldd %1\n\ttfr d,x\n=\n\tldx %1\n====\n# Get rid of silly jumps\n#17\n\tbra L%1\n;\nL%1:\n=\n;\nL%1:\n====\n#18\n\tbra L%1\nL%1:\n=\n;\nL%1:\n====\n# Skip some X to D transfers\n#19\n\ttfr x,d\n\tstd %1\n=\n\tstx %1\n====\n# Lose some silly X index operations\n#20\n\tldx #%1\n\tldd %2\n\tstd 0,x\n=\n\tldd %2\n\tstd %1\n====\n#21\n\tldd #%1\n\taddd #%2\n\ttfr d,x\n\tldd %3\n\tstd 0,x\n=\n\tldd %3\n\tstd %1+%2\n====\n#22\n\tldx #%1\n\tldd 0,x\n=\n\tldd %1\n====\n#23\n\tldd #%1\n\taddd #%2\n\ttfr d,x\n\tldd 0,x\n=\n\tldd %1+%2\n====\n# Simplify some X offsets\n#24\n\tldd %1\n\taddd #%2\n\ttfr d,x\n\tldd %3\n\tstd 0,x\n=\n\tldx %1\n\tldd %3\n\tstd %2,x\n====\n#25\n\tldd %1\n\taddd #%2\n\ttfr d,x\n\tldd 0,x\n=\n\tldx %1\n\tldd %2,x\n====\n# Optmise << 1\n#26\n\tpshs d\n\tldd #1\n\tlbsr __shl\n=\n\taslb\n\trola\n====\n"
  },
  {
    "path": "64_6809_Target/misc.c",
    "content": "#include <stdio.h>\n#include <unistd.h>\n#include \"defs.h\"\n#include \"data.h\"\n#include \"parse.h\"\n\n// Miscellaneous functions\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Print out fatal messages\nvoid fatal(char *s) {\n  fprintf(stderr, \"%s on line %d of %s\\n\", s, Line, Infilename);\n  exit(1);\n}\n\nvoid fatals(char *s1, char *s2) {\n  fprintf(stderr, \"%s:%s on line %d of %s\\n\", s1, s2, Line, Infilename);\n  exit(1);\n}\n\nvoid fatald(char *s, int d) {\n  fprintf(stderr, \"%s:%d on line %d of %s\\n\", s, d, Line, Infilename);\n  exit(1);\n}\n\nvoid fatalc(char *s, int c) {\n  fprintf(stderr, \"%s:%c on line %d of %s\\n\", s, c, Line, Infilename);\n  exit(1);\n}\n\n// Read at most count-1 characters from the\n// f FILE and store them in the s buffer.\n// Terminate the s buffer with a NUL.\n// Return NULL if unable to read or an EOF.\n// Else, return the original s pointer pointer.\nchar *fgetstr(char *s, size_t count, FILE * f) {\n  size_t i = count;\n  size_t err;\n  char ch;\n  char *ret = s;\n\n  while (i-- != 0) {\n    err= fread(&ch, 1, 1, f);\n    if (err!=1) {\n      if (s == ret)\n        return(NULL);\n      break;\n    }\n    *s++ = ch;\n    if (ch == 0)\n      break;\n  }\n  *s = 0;\n  return(ferror(f) ? (char *) NULL : ret);\n}\n"
  },
  {
    "path": "64_6809_Target/misc.h",
    "content": "/* misc.c */\nvoid fatal(char *s);\nvoid fatals(char *s1, char *s2);\nvoid fatald(char *s, int d);\nvoid fatalc(char *s, int c);\nchar *fgetstr(char *s, size_t count, FILE * f);\n"
  },
  {
    "path": "64_6809_Target/opt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"tree.h\"\n\n// AST Tree Optimisation Code\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Fold an AST tree with a unary operator\n// and one INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold1(struct ASTnode *n) {\n  int val;\n\n  // Get the child value. Do the\n  // operation if recognised.\n  // Return the new leaf node.\n  val = n->left->a_intvalue;\n  switch (n->op) {\n    case A_WIDEN:\n      break;\n    case A_INVERT:\n      val = ~val;\n      break;\n    case A_LOGNOT:\n      val = !val;\n      break;\n    case A_SCALE:\n      val = val * n->a_intvalue;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Fold an AST tree with a binary operator\n// and two A_INTLIT children. Return either \n// the original tree or a new leaf node.\nstatic struct ASTnode *fold2(struct ASTnode *n) {\n  int val, leftval, rightval;\n\n  // Get the values from each child\n  leftval = n->left->a_intvalue;\n  rightval = n->right->a_intvalue;\n\n  // Perform some of the binary operations.\n  // For any AST op we can't do, return\n  // the original tree.\n  switch (n->op) {\n    case A_ADD:\n      val = leftval + rightval;\n      break;\n    case A_SUBTRACT:\n      val = leftval - rightval;\n      break;\n    case A_MULTIPLY:\n      val = leftval * rightval;\n      break;\n    case A_DIVIDE:\n      // Don't try to divide by zero.\n      if (rightval == 0)\n\treturn (n);\n      val = leftval / rightval;\n      break;\n    case A_AND:\n      val = leftval & rightval;\n      break;\n    case A_OR:\n      val = leftval | rightval;\n      break;\n    case A_XOR:\n      val = leftval ^ rightval;\n      break;\n    case A_LSHIFT:\n      val = leftval << rightval;\n      break;\n    case A_RSHIFT:\n      val = leftval >> rightval;\n      break;\n    default:\n      return (n);\n  }\n\n  // Return a leaf node with the new value\n  return (mkastleaf(A_INTLIT, n->type, NULL, NULL, val));\n}\n\n// Optimise an AST tree with\n// a depth-first node traversal\nstruct ASTnode *optimise(struct ASTnode *n) {\n\n  if (n == NULL) return (NULL);\n\n  // Optimise the left child then the right\n  n->left = optimise(n->left);\n  if (n->left!=NULL) n->leftid= n->left->nodeid;\n  n->right = optimise(n->right);\n  if (n->right!=NULL) n->rightid= n->right->nodeid;\n\n  // Fold literal constants:\n  // If both children are A_INTLITs, do a fold2()\n  if (n->left && n->left->op == A_INTLIT) {\n    if (n->right && n->right->op == A_INTLIT)\n      n = fold2(n);\n    else\n      // If only the left is A_INTLIT, do a fold1()\n      n = fold1(n);\n  }\n\n  // Return the possibly modified tree\n  return (n);\n}\n"
  },
  {
    "path": "64_6809_Target/opt.h",
    "content": "/* opt.c */\nstruct ASTnode *optimise(struct ASTnode *n);\n"
  },
  {
    "path": "64_6809_Target/parse.c",
    "content": "#include \"defs.h\"\n#define extern_\n#include \"data.h\"\n#undef extern_\n#include \"decl.h\"\n#include \"gen.h\"\n#include \"misc.h\"\n#include \"sym.h\"\n#include \"tree.h\"\n\n// C parser front-end.\n// Copyright (c) 2023 Warren Toomey, GPL3\n\n#ifdef DEBUG\nvoid print_token(struct token *t) {\n    switch (t->token) {\n    case T_INTLIT:\n    case T_CHARLIT:\n      printf(\"%02X: %d\\n\", t->token, t->intvalue);\n      break;\n    case T_STRLIT:\n      printf(\"%02X: \\\"%s\\\"\\n\", t->token, Text);\n      break;\n    case T_FILENAME:\n      printf(\"%02X: filename \\\"%s\\\"\\n\", t->token, Text);\n      break;\n    case T_LINENUM:\n      printf(\"%02X: linenum %d\\n\", t->token, t->intvalue);\n      break;\n    case T_IDENT:\n      printf(\"%02X: %s\\n\", t->token, Text);\n      break;\n    default:\n      printf(\"%02X: %s\\n\", t->token, Tstring[t->token]);\n    }\n}\n#endif\n\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\nint scan(struct token *t) {\n  int intvalue;\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->tokstr = Peektoken.tokstr;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n#ifdef DEBUG\n    print_token(t);\n#endif\n    return (1);\n  }\n\n  // We loop because we don't want to return\n  // T_FILENAME or T_LINENUM tokens\n  while (1) {\n    t->token = fgetc(stdin);\n    if (t->token == EOF) {\n      t->token = T_EOF;\n      break;\n    }\n\n    switch (t->token) {\n    case T_LINENUM:\n      fread(&Line, sizeof(int), 1, stdin);\n      continue;\n    case T_FILENAME:\n      if (Infilename!=NULL) free(Infilename);\n      fgetstr(Text, TEXTLEN + 1, stdin);\n      Infilename= strdup(Text);\n      continue;\n    case T_INTLIT:\n    case T_CHARLIT:\n      fread(&intvalue, sizeof(int), 1, stdin);\n      t->intvalue = intvalue;\n      break;\n    case T_STRLIT:\n    case T_IDENT:\n      fgetstr(Text, TEXTLEN + 1, stdin);\n      break;\n    }\n#ifdef DEBUG\n    print_token(t);\n#endif\n    return (1);\n  }\n  return(0);\n}\n\n// Ensure that the current token is t,\n// and fetch the next token. Otherwise\n// throw an error \nvoid match(int t, char *what) {\n  if (Token.token == t) {\n    scan(&Token);\n  } else {\n    fatals(\"Expected\", what);\n  }\n}\n\n// Match a semicolon and fetch the next token\nvoid semi(void) {\n  match(T_SEMI, \";\");\n}\n\n// Match a left brace and fetch the next token\nvoid lbrace(void) {\n  match(T_LBRACE, \"{\");\n}\n\n// Match a right brace and fetch the next token\nvoid rbrace(void) {\n  match(T_RBRACE, \"}\");\n}\n\n// Match a left parenthesis and fetch the next token\nvoid lparen(void) {\n  match(T_LPAREN, \"(\");\n}\n\n// Match a right parenthesis and fetch the next token\nvoid rparen(void) {\n  match(T_RPAREN, \")\");\n}\n\n// Match an identifier and fetch the next token\nvoid ident(void) {\n  match(T_IDENT, \"identifier\");\n}\n\n// Match a comma and fetch the next token\nvoid comma(void) {\n  match(T_COMMA, \"comma\");\n}\n\n// Seralise an AST to Outfile\nvoid serialiseAST(struct ASTnode *tree) {\n  if (tree==NULL) return;\n\n  // Dump this node\n  fwrite(tree, sizeof(struct ASTnode), 1, Outfile);\n\n  // Dump any literal string/identifier\n  if (tree->name!=NULL) {\n    fputs(tree->name, Outfile);\n    fputc(0, Outfile);\n  }\n\n  // Dump all the children\n  serialiseAST(tree->left);\n  serialiseAST(tree->mid);\n  serialiseAST(tree->right);\n}\n\n// Parse the token stream on stdin\n// and output serialised ASTs and\n// a symbol table.\nint main(int argc, char **argv) {\n\n  if (argc <2 || argc >3) {\n    fprintf(stderr, \"Usage: %s symfile <astfile>\\n\", argv[0]);\n    fprintf(stderr, \"  ASTs on stdout if astfile not specified\\n\");\n    exit(1);\n  }\n\n  if (argc==3) {\n    Outfile= fopen(argv[2], \"w\");\n    if (Outfile == NULL) {\n      fprintf(stderr, \"Can't create %s\\n\", argv[2]); exit(1);\n    }\n  } else \n    Outfile= stdout;\n\n  Symfile= fopen(argv[1], \"w+\");\n  if (Symfile == NULL) {\n    fprintf(stderr, \"Can't create %s\\n\", argv[1]); exit(1);\n  }\n\n  freeSymtable();\t\t// Clear the symbol table\n  scan(&Token);                 // Get the first token from the input\n  Peektoken.token = 0;\t\t// and set there is no lookahead token\n  global_declarations();        // Parse the global declarations\n  flushSymtable();\t\t// Flush any residual symbols\n  fclose(Symfile);\n  exit(0);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/parse.h",
    "content": "/* parse.c */\nint scan(struct token *t);\nvoid match(int t, char *what);\nvoid semi(void);\nvoid lbrace(void);\nvoid rbrace(void);\nvoid lparen(void);\nvoid rparen(void);\nvoid ident(void);\nvoid comma(void);\nvoid serialiseAST(struct ASTnode *tree);\n"
  },
  {
    "path": "64_6809_Target/scan.c",
    "content": "#include \"defs.h\"\n#include \"misc.h\"\n\n// Lexical scanning\n// Copyright (c) 2019 Warren Toomey, GPL3\n\nint Line = 1;                   // Current line number\nint Newlinenum=0;\t\t// Flag: has line number changed\nint Linestart = 1;              // True if at start of a line\nint Putback = '\\n';             // Character put back by scanner\nchar *Infilename;               // Name of file we are parsing\nint Newfilename=0;\t\t// Flag: has filename changed\nFILE *Infile;                   // Input file struct\nstruct token Token;             // Last token scanned\nstruct token Peektoken;         // A look-ahead token\nchar Text[TEXTLEN + 1];         // Last identifier scanned\n\nint scan(struct token *t, int nocpp);\n\n// Return the position of character c\n// in string s, or -1 if c not found\nstatic int chrpos(char *s, int c) {\n  int i;\n  for (i = 0; s[i] != '\\0'; i++)\n    if (s[i] == (char) c)\n      return (i);\n  return (-1);\n}\n\n// Get the next character from the input file.\nstatic int next(void) {\n  int c, l;\n\n  if (Putback) {\t\t// Use the character put\n    c = Putback;\t\t// back if there is one\n    Putback = 0;\n    return (c);\n  }\n\n  c = fgetc(Infile);\t\t// Read from input file\n\n  while (Linestart && c == '#') {\t// We've hit a pre-processor statement\n    Linestart = 0;\t\t// No longer at the start of the line\n    scan(&Token, 1);\t\t// Get the line number into l\n    if (Token.token != T_INTLIT)\n      fatals(\"Expecting pre-processor line number, got:\", Text);\n    l = Token.intvalue;\n\n    scan(&Token, 1);\t\t// Get the filename in Text\n    if (Token.token != T_STRLIT)\n      fatals(\"Expecting pre-processor file name, got:\", Text);\n\n    if (Text[0] != '<') {\t// If this is a real filename\n      if (strcmp(Text, Infilename)) {\t// and not the one we have now\n\tfree(Infilename);\n\tInfilename = strdup(Text);\t// save it. Then update the line num\n        Newfilename=1;\n      }\n      Line = l;\n      Newlinenum=1;\n    }\n\n    while ((c = fgetc(Infile)) != '\\n');\t// Skip to the end of the line\n    c = fgetc(Infile);\t\t// and get the next character\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n\n  Linestart = 0;\t\t// No longer at the start of the line\n  if ('\\n' == c) {\n    Line++;\t\t\t// Increment line count\n    Newlinenum=1;\n    Linestart = 1;\t\t// Now back at the start of the line\n  }\n  return (c);\n}\n\n// Put back an unwanted character\nstatic void putback(int c) {\n  Putback = c;\n}\n\n// Skip past input that we don't need to deal with, \n// i.e. whitespace, newlines. Return the first\n// character we do need to deal with.\nstatic int skip(void) {\n  int c;\n\n  c = next();\n  while (' ' == c || '\\t' == c || '\\n' == c || '\\r' == c || '\\f' == c) {\n    c = next();\n  }\n  return (c);\n}\n\n// Read in a hexadecimal constant from the input\nstatic int hexchar(void) {\n  int c, h, n = 0, f = 0;\n\n  // Loop getting characters\n  while (isxdigit(c = next())) {\n    // Convert from char to int value\n    h = chrpos(\"0123456789abcdef\", tolower(c));\n\n    // Add to running hex value\n    n = n * 16 + h;\n    f = 1;\n  }\n\n  // We hit a non-hex character, put it back\n  putback(c);\n\n  // Flag tells us we never saw any hex characters\n  if (!f)\n    fatal(\"missing digits after '\\\\x'\");\n  if (n > 255)\n    fatal(\"value out of range after '\\\\x'\");\n\n  return (n);\n}\n\n// Return the next character from a character\n// or string literal. Also return if this\n// character was quoted with a preceding backslash\nstatic int scanch(int *slash) {\n  int i, c, c2;\n  *slash=0;\n\n  // Get the next input character and interpret\n  // metacharacters that start with a backslash\n  c = next();\n  if (c == '\\\\') {\n    *slash=1;\n    switch (c = next()) {\n      case 'a':\n\treturn ('\\a');\n      case 'b':\n\treturn ('\\b');\n      case 'f':\n\treturn ('\\f');\n      case 'n':\n\treturn ('\\n');\n      case 'r':\n\treturn ('\\r');\n      case 't':\n\treturn ('\\t');\n      case 'v':\n\treturn ('\\v');\n      case '\\\\':\n\treturn ('\\\\');\n      case '\"':\n\treturn ('\"');\n      case '\\'':\n\treturn ('\\'');\n\n\t// Deal with octal constants by reading in\n\t// characters until we hit a non-octal digit.\n\t// Build up the octal value in c2 and count\n\t// # digits in i. Permit only 3 octal digits.\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n\tfor (i = c2 = 0; isdigit(c) && c < '8'; c = next()) {\n\t  if (++i > 3)\n\t    break;\n\t  c2 = c2 * 8 + (c - '0');\n\t}\n\n\tputback(c);\t\t// Put back the first non-octal char\n\treturn (c2);\n      case 'x':\n\treturn (hexchar());\n      default:\n        fatalc(\"unknown escape sequence\", c);\n    }\n  }\n  return (c);\t\t\t// Just an ordinary old character!\n}\n\n// Scan and return an integer literal\n// value from the input file.\nstatic int scanint(int c) {\n  int k, val = 0, radix = 10;\n\n  // Assume the radix is 10, but if it starts with 0\n  if (c == '0') {\n    // and the next character is 'x', it's radix 16\n    if ((c = next()) == 'x') {\n      radix = 16;\n      c = next();\n    } else\n      // Otherwise, it's radix 8\n      radix = 8;\n\n  }\n  // Convert each character into an int value\n  while ((k = chrpos(\"0123456789abcdef\", tolower(c))) >= 0) {\n    if (k >= radix)\n      fatalc(\"invalid digit in integer literal\", c);\n    val = val * radix + k;\n    c = next();\n  }\n\n  // We hit a non-integer character, put it back.\n  putback(c);\n  return (val);\n}\n\n// Scan in a string literal from the input file,\n// and store it in buf[]. Return the length of\n// the string. \nstatic int scanstr(char *buf) {\n  int i, c;\n  int slash;\n\n  // Loop while we have enough buffer space\n  for (i = 0; i < TEXTLEN - 1; i++) {\n    // Get the next char and append to buf\n    // Return when we hit the ending double quote\n    // (which wasn't quoted with a backslash)\n    c = scanch(&slash);\n    if (c == '\"' && slash==0) {\n      buf[i] = 0;\n      return (i);\n    }\n    buf[i] = (char) c;\n  }\n\n  // Ran out of buf[] space\n  fatal(\"String literal too long\");\n  return (0);\n}\n\n// Scan an identifier from the input file and\n// store it in buf[]. Return the identifier's length\nstatic int scanident(int c, char *buf, int lim) {\n  int i = 0;\n\n  // Allow digits, alpha and underscores\n  while (isalpha(c) || isdigit(c) || '_' == c) {\n    // Error if we hit the identifier length limit,\n    // else append to buf[] and get next character\n    if (lim - 1 == i) {\n      fatal(\"Identifier too long\");\n    } else if (i < lim - 1) {\n      buf[i++] = (char) c;\n    }\n    c = next();\n  }\n\n  // We hit a non-valid character, put it back.\n  // NUL-terminate the buf[] and return the length\n  putback(c);\n  buf[i] = '\\0';\n  return (i);\n}\n\n// Given a word from the input, return the matching\n// keyword token number or 0 if it's not a keyword.\n// Switch on the first letter so that we don't have\n// to waste time strcmp()ing against all the keywords.\nstatic int keyword(char *s) {\n  switch (*s) {\n    case 'b':\n      if (!strcmp(s, \"break\"))\n\treturn (T_BREAK);\n      break;\n    case 'c':\n      if (!strcmp(s, \"case\"))\n\treturn (T_CASE);\n      if (!strcmp(s, \"char\"))\n\treturn (T_CHAR);\n      if (!strcmp(s, \"continue\"))\n\treturn (T_CONTINUE);\n      break;\n    case 'd':\n      if (!strcmp(s, \"default\"))\n\treturn (T_DEFAULT);\n      break;\n    case 'e':\n      if (!strcmp(s, \"else\"))\n\treturn (T_ELSE);\n      if (!strcmp(s, \"enum\"))\n\treturn (T_ENUM);\n      if (!strcmp(s, \"extern\"))\n\treturn (T_EXTERN);\n      break;\n    case 'f':\n      if (!strcmp(s, \"for\"))\n\treturn (T_FOR);\n      break;\n    case 'i':\n      if (!strcmp(s, \"if\"))\n\treturn (T_IF);\n      if (!strcmp(s, \"int\"))\n\treturn (T_INT);\n      break;\n    case 'l':\n      if (!strcmp(s, \"long\"))\n\treturn (T_LONG);\n      break;\n    case 'r':\n      if (!strcmp(s, \"return\"))\n\treturn (T_RETURN);\n      break;\n    case 's':\n      if (!strcmp(s, \"sizeof\"))\n\treturn (T_SIZEOF);\n      if (!strcmp(s, \"static\"))\n\treturn (T_STATIC);\n      if (!strcmp(s, \"struct\"))\n\treturn (T_STRUCT);\n      if (!strcmp(s, \"switch\"))\n\treturn (T_SWITCH);\n      break;\n    case 't':\n      if (!strcmp(s, \"typedef\"))\n\treturn (T_TYPEDEF);\n      break;\n    case 'u':\n      if (!strcmp(s, \"union\"))\n\treturn (T_UNION);\n      break;\n    case 'v':\n      if (!strcmp(s, \"void\")) {\n\treturn (T_VOID);\n}\n      break;\n    case 'w':\n      if (!strcmp(s, \"while\"))\n\treturn (T_WHILE);\n      break;\n  }\n  return (0);\n}\n\n#ifdef DEBUG\n// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\", \"%=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \"<\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"%\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"...\", \"charlit\", \"filename\", \"linenum\"\n};\n#endif\n\n// Scan and return the next token found in the input.\n// Return 1 if token valid, 0 if no tokens left.\n// If nocpp, don't return on new filenames or line numbers.\n// This is because we use scan() when parsing new filenames\n// and line numbers :-)\nint scan(struct token *t, int nocpp) {\n  int c, tokentype;\n  int slash;\n\n  // Skip whitespace\n  c = skip();\n\n  if (nocpp==0) {\n    // If the filename changed, return the filename\n    if (Newfilename) {\n      t->token = T_FILENAME;\n      Newfilename=0;\n      putback(c);\n      return (1);\n    }\n\n    // If the line number changed, return the line number\n    if (Newlinenum) {\n      t->intvalue = Line;\n      t->token = T_LINENUM;\n      Newlinenum=0;\n      putback(c);\n      return (1);\n    }\n  }\n\n  // If we have a lookahead token, return this token\n  if (Peektoken.token != 0) {\n    t->token = Peektoken.token;\n    t->intvalue = Peektoken.intvalue;\n    Peektoken.token = 0;\n    return (1);\n  }\n\n  // Determine the token based on\n  // the input character\n  switch (c) {\n    case EOF:\n      t->token = T_EOF;\n      return (0);\n    case '+':\n      if ((c = next()) == '+') {\n\tt->token = T_INC;\n      } else if (c == '=') {\n\tt->token = T_ASPLUS;\n      } else {\n\tputback(c);\n\tt->token = T_PLUS;\n      }\n      break;\n    case '-':\n      if ((c = next()) == '-') {\n\tt->token = T_DEC;\n      } else if (c == '>') {\n\tt->token = T_ARROW;\n      } else if (c == '=') {\n\tt->token = T_ASMINUS;\n      } else if (isdigit(c)) {\t// Negative int literal\n\tt->intvalue = -scanint(c);\n\tt->token = T_INTLIT;\n      } else {\n\tputback(c);\n\tt->token = T_MINUS;\n      }\n      break;\n    case '*':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSTAR;\n      } else {\n\tputback(c);\n\tt->token = T_STAR;\n      }\n      break;\n    case '/':\n      if ((c = next()) == '=') {\n\tt->token = T_ASSLASH;\n      } else {\n\tputback(c);\n\tt->token = T_SLASH;\n      }\n      break;\n    case '%':\n      if ((c = next()) == '=') {\n\tt->token = T_ASMOD;\n      } else {\n\tputback(c);\n\tt->token = T_MOD;\n      }\n      break;\n    case ';':\n      t->token = T_SEMI;\n      break;\n    case '{':\n      t->token = T_LBRACE;\n      break;\n    case '}':\n      t->token = T_RBRACE;\n      break;\n    case '(':\n      t->token = T_LPAREN;\n      break;\n    case ')':\n      t->token = T_RPAREN;\n      break;\n    case '[':\n      t->token = T_LBRACKET;\n      break;\n    case ']':\n      t->token = T_RBRACKET;\n      break;\n    case '~':\n      t->token = T_INVERT;\n      break;\n    case '^':\n      t->token = T_XOR;\n      break;\n    case ',':\n      t->token = T_COMMA;\n      break;\n    case '.':\n      if ((c = next()) == '.') {\n        t->token = T_ELLIPSIS;\n        if ((c = next()) != '.')\n\t  fatal(\"Expected '...', only got '..'\\n\");\n      } else {\n\tputback(c);\n        t->token = T_DOT;\n      }\n      break;\n    case ':':\n      t->token = T_COLON;\n      break;\n    case '?':\n      t->token = T_QUESTION;\n      break;\n    case '=':\n      if ((c = next()) == '=') {\n\tt->token = T_EQ;\n      } else {\n\tputback(c);\n\tt->token = T_ASSIGN;\n      }\n      break;\n    case '!':\n      if ((c = next()) == '=') {\n\tt->token = T_NE;\n      } else {\n\tputback(c);\n\tt->token = T_LOGNOT;\n      }\n      break;\n    case '<':\n      if ((c = next()) == '=') {\n\tt->token = T_LE;\n      } else if (c == '<') {\n\tt->token = T_LSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_LT;\n      }\n      break;\n    case '>':\n      if ((c = next()) == '=') {\n\tt->token = T_GE;\n      } else if (c == '>') {\n\tt->token = T_RSHIFT;\n      } else {\n\tputback(c);\n\tt->token = T_GT;\n      }\n      break;\n    case '&':\n      if ((c = next()) == '&') {\n\tt->token = T_LOGAND;\n      } else {\n\tputback(c);\n\tt->token = T_AMPER;\n      }\n      break;\n    case '|':\n      if ((c = next()) == '|') {\n\tt->token = T_LOGOR;\n      } else {\n\tputback(c);\n\tt->token = T_OR;\n      }\n      break;\n    case '\\'':\n      // If it's a quote, scan in the\n      // literal character value and\n      // the trailing quote\n      t->intvalue = scanch(&slash);\n      t->token = T_CHARLIT;\n      if (next() != '\\'')\n\tfatal(\"Expected '\\\\'' at end of char literal\");\n      break;\n    case '\"':\n      // Scan in a literal string\n      scanstr(Text);\n      t->token = T_STRLIT;\n      break;\n    default:\n      // If it's a digit, scan the\n      // literal integer value in\n      if (isdigit(c)) {\n\tt->intvalue = scanint(c);\n\tt->token = T_INTLIT;\n\tbreak;\n      } else if (isalpha(c) || '_' == c) {\n\t// Read in a keyword or identifier\n\tscanident(c, Text, TEXTLEN);\n\n\t// If it's a recognised keyword, return that token\n\tif ((tokentype = keyword(Text)) != 0) {\n\t  t->token = tokentype;\n\t  break;\n\t}\n\t// Not a recognised keyword, so it must be an identifier\n\tt->token = T_IDENT;\n\tbreak;\n      }\n      // The character isn't part of any recognised token, error\n      fatalc(\"Unrecognised character\", c);\n  }\n\n  // We found a token\n  return (1);\n}\n\n// Read lines of code from stdin and output\n// a token stream\nint main() {\n  int i;\n\n  Infile= stdin;\n  Infilename = strdup(\"\");\t// Cpp hasn't told us the filename yet\n  Peektoken.token = 0;          // Set there is no lookahead token\n  scan(&Token, 0);              // Get the first token from the input\n\n  // Loop getting more tokens\n  while (Token.token != T_EOF) {\n\n    // Output a binary stream of tokens to standard output.\n    // T_INTLIT tokens are followed by the n-byte literal value.\n    // T_STRLIT and T_IDENT tokens are followed by a NUL-terminated string.\n    fputc(Token.token, stdout);\n    switch (Token.token) {\n    case T_INTLIT:\n    case T_CHARLIT:\n      i= Token.intvalue;\n      fwrite(&i, sizeof(int), 1, stdout);\n      // fprintf(stderr, \"%02X: %d\\n\", Token.token, Token.intvalue);\n      break;\n    case T_STRLIT:\n      fputs(Text, stdout);\n      fputc(0, stdout);\n      // fprintf(stderr, \"%02X: \\\"%s\\\"\\n\", Token.token, Text);\n      break;\n    case T_IDENT:\n      fputs(Text, stdout);\n      fputc(0, stdout);\n      // fprintf(stderr, \"%02X: %s\\n\", Token.token, Text);\n      break;\n    case T_FILENAME:\n      fputs(Infilename, stdout);\n      fputc(0, stdout);\n      // fprintf(stderr, \"%02X: %s\\n\", Token.token, Infilename);\n      break;\n    case T_LINENUM:\n      fwrite(&Line, sizeof(int), 1, stdout);\n      // fprintf(stderr, \"%02X: %d\\n\", Token.token, Line);\n      break;\n    default:\n      // fprintf(stderr, \"%02X: %s\\n\", Token.token, Tstring[Token.token]);\n    }\n    scan(&Token, 0);\n  }\n  \n  exit(0);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/stmt.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"decl.h\"\n#include \"expr.h\"\n#include \"misc.h\"\n#include \"opt.h\"\n#include \"parse.h\"\n#include \"stmt.h\"\n#include \"sym.h\"\n#include \"tree.h\"\n#include \"types.h\"\n\n// Parsing of statements\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Prototypes\nstatic struct ASTnode *single_statement(void);\n\n// compound_statement:          // empty, i.e. no statement\n//      |      statement\n//      |      statement statements\n//      ;\n//\n// statement: declaration\n//      |     expression_statement\n//      |     function_call\n//      |     if_statement\n//      |     while_statement\n//      |     for_statement\n//      |     return_statement\n//      ;\n\n\n// if_statement: if_head\n//      |        if_head 'else' statement\n//      ;\n//\n// if_head: 'if' '(' true_false_expression ')' statement  ;\n//\n// Parse an IF statement including any\n// optional ELSE clause and return its AST\nstatic struct ASTnode *if_statement(void) {\n  struct ASTnode *condAST, *trueAST, *falseAST = NULL;\n\n  // Ensure we have 'if' '('\n  match(T_IF, \"if\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-boolean operation to be boolean.\n  condAST = binexpr(0);\n  if (condAST->op != A_LOGOR && condAST->op != A_LOGAND &&\n\t\t(condAST->op < A_EQ || condAST->op > A_GE))\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement\n  trueAST = single_statement();\n\n  // If we have an 'else', skip it\n  // and get the AST for the statement\n  if (Token.token == T_ELSE) {\n    scan(&Token);\n    falseAST = single_statement();\n  }\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_IF, P_NONE, NULL, condAST, trueAST, falseAST, NULL, 0));\n}\n\n\n// while_statement: 'while' '(' true_false_expression ')' statement  ;\n//\n// Parse a WHILE statement and return its AST\nstatic struct ASTnode *while_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n\n  // Ensure we have 'while' '('\n  match(T_WHILE, \"while\");\n  lparen();\n\n  // Parse the following expression\n  // and the ')' following. Force a\n  // non-boolean operation to be boolean.\n  condAST = binexpr(0);\n  if (condAST->op != A_LOGOR && condAST->op != A_LOGAND &&\n\t\t(condAST->op < A_EQ || condAST->op > A_GE))\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  rparen();\n\n  // Get the AST for the statement.\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Build and return the AST for this statement\n  return (mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, bodyAST, NULL, 0));\n}\n\n// for_statement: 'for' '(' expression_list ';'\n//                          true_false_expression ';'\n//                          expression_list ')' statement  ;\n//\n// Parse a FOR statement and return its AST\nstatic struct ASTnode *for_statement(void) {\n  struct ASTnode *condAST, *bodyAST;\n  struct ASTnode *preopAST, *postopAST;\n  struct ASTnode *tree;\n\n  // Ensure we have 'for' '('\n  match(T_FOR, \"for\");\n  lparen();\n\n  // Get the pre_op expression and the ';'\n  preopAST = expression_list(T_SEMI);\n  semi();\n\n  // Get the condition and the ';'. Force a\n  // non-boolean operation to be boolean.\n  condAST = binexpr(0);\n  if (condAST->op != A_LOGOR && condAST->op != A_LOGAND &&\n\t\t(condAST->op < A_EQ || condAST->op > A_GE))\n    condAST =\n      mkastunary(A_TOBOOL, condAST->type, condAST->ctype, condAST, NULL, 0);\n  semi();\n\n  // Get the post_op expression and the ')'\n  postopAST = expression_list(T_RPAREN);\n  rparen();\n\n  // Get the statement which is the body\n  // Update the loop depth in the process\n  Looplevel++;\n  bodyAST = single_statement();\n  Looplevel--;\n\n  // Glue the statement and the postop tree\n  tree = mkastnode(A_GLUE, P_NONE, NULL, bodyAST, NULL, postopAST, NULL, 0);\n\n  // Make a WHILE loop with the condition and this new body\n  tree = mkastnode(A_WHILE, P_NONE, NULL, condAST, NULL, tree, NULL, 0);\n\n  // And glue the preop tree to the A_WHILE tree\n  return (mkastnode(A_GLUE, P_NONE, NULL, preopAST, NULL, tree, NULL, 0));\n}\n\n// return_statement: 'return' '(' expression ')'  ;\n//\n// Parse a return statement and return its AST\nstatic struct ASTnode *return_statement(void) {\n  struct ASTnode *tree= NULL;\n\n  // Ensure we have 'return'\n  match(T_RETURN, \"return\");\n\n  // See if we have a return value\n  if (Token.token == T_LPAREN) {\n    // Can't return a value if function returns P_VOID\n    if (Functionid->type == P_VOID)\n      fatal(\"Can't return from a void function\");\n\n    // Skip the left parenthesis\n    lparen();\n\n    // Parse the following expression\n    tree = binexpr(0);\n\n    // Ensure this is compatible with the function's type\n    tree = modify_type(tree, Functionid->type, Functionid->ctype, 0);\n    if (tree == NULL)\n      fatal(\"Incompatible type to return\");\n\n    // Get the ')'\n    rparen();\n  }\n\n  // Add on the A_RETURN node\n  tree = mkastunary(A_RETURN, P_NONE, NULL, tree, NULL, 0);\n\n  // Get the ';'\n  semi();\n  return (tree);\n}\n\n// break_statement: 'break' ;\n//\n// Parse a break statement and return its AST\nstatic struct ASTnode *break_statement(void) {\n\n  if (Looplevel == 0 && Switchlevel == 0)\n    fatal(\"no loop or switch to break out from\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_BREAK, P_NONE, NULL, NULL, 0));\n}\n\n// continue_statement: 'continue' ;\n//\n// Parse a continue statement and return its AST\nstatic struct ASTnode *continue_statement(void) {\n\n  if (Looplevel == 0)\n    fatal(\"no loop to continue to\");\n  scan(&Token);\n  semi();\n  return (mkastleaf(A_CONTINUE, P_NONE, NULL, NULL, 0));\n}\n\n// Parse a switch statement and return its AST\nstatic struct ASTnode *switch_statement(void) {\n  struct ASTnode *left, *body, *n, *c;\n  struct ASTnode *casetree = NULL, *casetail;\n  int inloop = 1, casecount = 0;\n  int seendefault = 0;\n  int ASTop, casevalue;\n\n  // Skip the 'switch' and '('\n  scan(&Token);\n  lparen();\n\n  // Get the switch expression, the ')' and the '{'\n  left = binexpr(0);\n  rparen();\n  lbrace();\n\n  // Ensure that this is of int type\n  if (!inttype(left->type))\n    fatal(\"Switch expression is not of integer type\");\n\n  // If its type P_CHAR, widen it to P_INT\n  if (left->type == P_CHAR)\n    left= mkastunary(A_WIDEN, P_INT, NULL, left, NULL, 0);\n\n  // Build an A_SWITCH subtree with the expression as the child\n  n = mkastunary(A_SWITCH, P_NONE, NULL, left, NULL, 0);\n\n  // Now parse the cases\n  Switchlevel++;\n  while (inloop) {\n    switch (Token.token) {\n\t// Leave the loop when we hit a '}'\n      case T_RBRACE:\n\tif (casecount == 0)\n\t  fatal(\"No cases in switch\");\n\tinloop = 0;\n\tbreak;\n      case T_CASE:\n      case T_DEFAULT:\n\t// Ensure this isn't after a previous 'default'\n\tif (seendefault)\n\t  fatal(\"case or default after existing default\");\n\n\t// Set the AST operation. Scan the case value if required\n\tif (Token.token == T_DEFAULT) {\n\t  ASTop = A_DEFAULT;\n\t  seendefault = 1;\n\t  scan(&Token);\n\t} else {\n\t  ASTop = A_CASE;\n\t  scan(&Token);\n\t  left = binexpr(0);\n\n\t  // Ensure the case value is an integer literal\n\t  if (left->op != A_INTLIT)\n\t    fatal(\"Expecting integer literal for case value\");\n\t  casevalue = left->a_intvalue;\n\n\t  // Walk the list of existing case values to ensure\n\t  // that there isn't a duplicate case value\n\t  for (c = casetree; c != NULL; c = c->right)\n\t    if (casevalue == c->a_intvalue)\n\t      fatal(\"Duplicate case value\");\n\t}\n\n\t// Scan the ':' and increment the casecount\n\tmatch(T_COLON, \":\");\n\tcasecount++;\n\n\t// If the next token is a T_CASE, the existing case will fall\n\t// into the next case. Otherwise, parse the case body.\n\tif (Token.token == T_CASE)\n\t  body = NULL;\n\telse\n\t  body = compound_statement(1);\n\n\t// Build a sub-tree with any compound statement as the left child\n\t// and link it in to the growing A_CASE tree\n\tif (casetree == NULL) {\n\t  casetree = casetail =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t} else {\n\t  casetail->right =\n\t    mkastunary(ASTop, P_NONE, NULL, body, NULL, casevalue);\n\t  casetail->rightid= casetail->right->nodeid;\n\t  casetail = casetail->right;\n\t}\n\tbreak;\n      default:\n\tfatals(\"Unexpected token in switch\", Tstring[Token.token]);\n    }\n  }\n  Switchlevel--;\n\n  // We have a sub-tree with the cases and any default. Put the\n  // case count into the A_SWITCH node and attach the case tree.\n  n->a_intvalue = casecount;\n  n->right = casetree;\n  n->rightid = casetree->nodeid;\n  rbrace();\n\n  return (n);\n}\n\n// Parse a single statement and return its AST.\nstatic struct ASTnode *single_statement(void) {\n  struct ASTnode *stmt;\n  struct symtable *ctype;\n  int linenum= Line;\n\n  switch (Token.token) {\n    case T_SEMI:\n      // An empty statement\n      semi();\n      break;\n    case T_LBRACE:\n      // We have a '{', so this is a compound statement\n      lbrace();\n      stmt = compound_statement(0);\n      stmt->linenum= linenum;\n      rbrace();\n      return (stmt);\n    case T_IDENT:\n      // We have to see if the identifier matches a typedef.\n      // If not, treat it as an expression.\n      // Otherwise, fall down to the parse_type() call.\n      if (findtypedef(Text) == NULL) {\n\tstmt = binexpr(0);\n        stmt->linenum= linenum;\n\tsemi();\n\treturn (stmt);\n      }\n    case T_CHAR:\n    case T_INT:\n    case T_LONG:\n    case T_STRUCT:\n    case T_UNION:\n    case T_ENUM:\n    case T_TYPEDEF:\n      // The beginning of a variable declaration list.\n      declaration_list(&ctype, V_LOCAL, T_SEMI, T_EOF, &stmt);\n      semi();\n      return (stmt);\t\t// Any assignments from the declarations\n    case T_IF:\n      stmt= if_statement(); stmt->linenum= linenum; return(stmt);\n    case T_WHILE:\n      stmt= while_statement(); stmt->linenum= linenum; return(stmt);\n    case T_FOR:\n      stmt= for_statement(); stmt->linenum= linenum; return(stmt);\n    case T_RETURN:\n      stmt= return_statement(); stmt->linenum= linenum; return(stmt);\n    case T_BREAK:\n      stmt= break_statement(); stmt->linenum= linenum; return(stmt);\n    case T_CONTINUE:\n      stmt= continue_statement(); stmt->linenum= linenum; return(stmt);\n    case T_SWITCH:\n      stmt= switch_statement(); stmt->linenum= linenum; return(stmt);\n    default:\n      // For now, see if this is an expression.\n      // This catches assignment statements.\n      stmt = binexpr(0);\n      stmt->linenum= linenum;\n      semi();\n      return (stmt);\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n\n// Parse a compound statement\n// and return its AST. If inswitch is true,\n// we look for a '}', 'case' or 'default' token\n// to end the parsing. Otherwise, look for\n// just a '}' to end the parsing.\nstruct ASTnode *compound_statement(int inswitch) {\n  struct ASTnode *left = NULL;\n  struct ASTnode *tree;\n\n  while (1) {\n    // Leave if we've hit the end token. We do this first to allow\n    // an empty compound statement\n    if (Token.token == T_RBRACE)\n      return (left);\n    if (inswitch && (Token.token == T_CASE || Token.token == T_DEFAULT))\n      return (left);\n\n    // Parse a single statement\n    tree = single_statement();\n\n    // For each new tree, either save it in left\n    // if left is empty, or glue the left and the\n    // new tree together\n    if (tree != NULL) {\n      if (left == NULL)\n\tleft = tree;\n      else {\n\tleft = mkastnode(A_GLUE, P_NONE, NULL, left, NULL, tree, NULL, 0);\n\n\t// To conserve memory, we try to optimise the single statement tree.\n\t// Then we serialise the tree and free it. We set the right pointer\n\t// in left NULL; this will stop the serialiser from descending into\n\t// the tree that we already serialised.\n\ttree = optimise(tree);\n\tserialiseAST(tree);\n\tfreetree(tree, 0);\n\tleft->right=NULL;\n      }\n    }\n  }\n  return (NULL);\t\t// Keep -Wall happy\n}\n"
  },
  {
    "path": "64_6809_Target/stmt.h",
    "content": "/* stmt.c */\nstruct ASTnode *compound_statement(int inswitch);\n"
  },
  {
    "path": "64_6809_Target/sym.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"misc.h\"\n#include \"tree.h\"\n#include \"types.h\"\n#include \"sym.h\"\n\n#undef MEMBDEBUG\n#undef DEBUG\n\n// Symbol table functions\n// Copyright (c) 2024 Warren Toomey, GPL3\n\n// We have two in-memory symbol tables. One is for\n// types (structs, unions, enums, typedefs); the\n// other is for variables and functions. These\n// cache symbols from the symbol file which have\n// been recently used.\n// There is also a temporary list which we build\n// before attaching to a symbol's member field.\n// This is used for structs, unions and enums.\n// It also holds the parameters and locals of\n// the function we are currently parsing.\n//\n// Symhead needs to be visible for cgen.c\n\nstruct symtable *Symhead = NULL;\nstatic struct symtable *Symtail = NULL;\nstatic struct symtable *Typehead = NULL;\nstatic struct symtable *Typetail = NULL;\nstatic struct symtable *Membhead = NULL;\nstatic struct symtable *Membtail = NULL;\n\n#ifdef DEBUG\nstatic void dumptable(struct symtable *head, int indent);\n\n// List of structural type strings\nchar *Sstring[] = {\n  \"variable\", \"function\", \"array\", \"enumval\", \"strlit\",\n  \"struct\", \"union\", \"enumtype\", \"typedef\", \"notype\"\n};\n\n// Dump a single symbol\nstatic void dumpsym(struct symtable *sym, int indent) {\n  int i;\n\n  for (i = 0; i < indent; i++)\n    printf(\" \");\n  switch (sym->type & (~0xf)) {\n  case P_VOID: printf(\"void \"); break;\n  case P_CHAR: printf(\"char \"); break;\n  case P_INT:  printf(\"int \"); break;\n  case P_LONG: printf(\"long \"); break;\n  case P_STRUCT:\n    printf(\"struct \");\n    if (sym->ctype && sym->ctype->name)\n      printf(\"%s \", sym->ctype->name);\n    break;\n  case P_UNION:\n    printf(\"union \");\n    if (sym->ctype && sym->ctype->name)\n      printf(\"%s \", sym->ctype->name);\n    break;\n  default:\n    printf(\"unknown type \");\n  }\n\n  for (i = 0; i < (sym->type & 0xf); i++) printf(\"*\");\n  printf(\"%s\", sym->name);\n\n  switch (sym->stype) {\n  case S_VARIABLE:\n    break;\n  case S_FUNCTION: printf(\"()\"); break;\n  case S_ARRAY:    printf(\"[]\"); break;\n  case S_STRUCT:   printf(\": struct\"); break;\n  case S_UNION:    printf(\": union\"); break;\n  case S_ENUMTYPE: printf(\": enum\"); break;\n  case S_ENUMVAL:  printf(\": enumval\"); break;\n  case S_TYPEDEF:  printf(\": typedef\"); break;\n  case S_STRLIT:   printf(\": strlit\"); break;\n  default:\t   printf(\" unknown stype\");\n  }\n\n  printf(\" id %d\", sym->id);\n\n  switch (sym->class) {\n  case V_GLOBAL: printf(\": global\"); break;\n  case V_LOCAL:  printf(\": local offset %d\", sym->st_posn); break;\n  case V_PARAM:  printf(\": param offset %d\", sym->st_posn); break;\n  case V_EXTERN: printf(\": extern\"); break;\n  case V_STATIC: printf(\": static\"); break;\n  case V_MEMBER: printf(\": member\"); break;\n  default: \t printf(\": unknown class\");\n  }\n\n  if (sym->st_hasaddr != 0) printf(\", hasaddr \");\n\n  switch (sym->stype) {\n  case S_VARIABLE: printf(\", size %d\", sym->size); break;\n  case S_FUNCTION: printf(\", %d params\", sym->nelems); break;\n  case S_ARRAY:    printf(\", %d elems, size %d\", sym->nelems, sym->size); break;\n  }\n\n  printf(\", ctypeid %d, nelems %d st_posn %d\\n\",\n\t sym->ctypeid, sym->nelems, sym->st_posn);\n\n  if (sym->member != NULL) dumptable(sym->member, 4);\n}\n\n// Dump one symbol table\nstatic void dumptable(struct symtable *head, int indent) {\n  struct symtable *sym;\n\n  for (sym = head; sym != NULL; sym = sym->next) dumpsym(sym, indent);\n}\n\nvoid dumpSymlists(void) {\n  fprintf(stderr, \"Typelist\\n\");\n  fprintf(stderr, \"--------\\n\");\n  dumptable(Typehead, 0);\n  fprintf(stderr, \"\\nSymlist\\n\");\n  fprintf(stderr, \"-------\\n\");\n  dumptable(Symhead, 0);\n  fprintf(stderr, \"\\nFunctionid\\n\");\n  fprintf(stderr, \"----------\\n\");\n  dumptable(Functionid, 0);\n  fprintf(stderr, \"\\nMemblist\\n\");\n  fprintf(stderr, \"--------\\n\");\n  dumptable(Membhead, 0);\n}\n#endif\n\n// Append a node to the singly-linked list pointed to by head or tail\nstatic void appendSym(struct symtable **head, struct symtable **tail,\n\t\t      struct symtable *node) {\n\n  // Check for valid pointers\n  if (head == NULL || tail == NULL || node == NULL)\n    fatal(\"Either head, tail or node is NULL in appendSym\");\n\n  // Append to the list\n  if (*tail) {\n    (*tail)->next = node; *tail = node;\n  } else\n    *head = *tail = node;\n  node->next = NULL;\n}\n\n// The last name we loaded from the symbol file\nstatic char SymText[TEXTLEN + 1];\n\n#ifdef WRITESYMS\n// Unique id for each symbol. We need this when serialising\n// so that the composite type of a variable can be found.\nstatic int Symid = 1;\n\n// For symbols which are not locals or parameters,\n// we point this at the symbol once created. This\n// allows us to e.g. add initial values or members.\n// When we come to make another non-local/param,\n// this gets flushed to disk.\n\nstruct symtable *thisSym = NULL;\n\n// When we are serialising symbols to the symbol table file,\n// track the one with the highest id. After each flushing\n// of the in-memory lists, record the highest id into skipSymid.\n// Then, on the next flush, don't write out symbols at or below\n// the skipSymid.\nstatic int highestSymid = 0;\nstatic int skipSymid = 0;\n\n// Serialise one symbol to the symbol table file\nstatic void serialiseSym(struct symtable *sym) {\n  struct symtable *memb;\n\n  if (sym->id > highestSymid) highestSymid = sym->id;\n\n  if (sym->id <= skipSymid) {\n#ifdef DEBUG\n    fprintf(stderr, \"NOT Writing %s %s id %d to disk\\n\",\n\t    Sstring[sym->stype], sym->name, sym->id);\n#endif\n    return;\n  }\n\n  // Output the symbol struct and the name\n  // once we are at the end of the file\n  fseek(Symfile, 0, SEEK_END);\n#ifdef DEBUG\n  fprintf(stderr, \"Writing %s %s id %d to disk offset %ld\\n\",\n\t  Sstring[sym->stype], sym->name, sym->id, ftell(Symfile));\n#endif\n  fwrite(sym, sizeof(struct symtable), 1, Symfile);\n  if (sym->name != NULL) {\n    fputs(sym->name, Symfile); fputc(0, Symfile);\n  }\n  // Output the initial values, if any\n  if (sym->initlist != NULL)\n    fwrite(sym->initlist, sizeof(int), sym->nelems, Symfile);\n\n  // Output the member symbols\n#ifdef DEBUG\n  if (sym->member != NULL) {\n    fprintf(stderr, \"%s has members\\n\", sym->name);\n  }\n#endif\n\n  for (memb = sym->member; memb != NULL; memb = memb->next)\n    serialiseSym(memb);\n}\n\n// Create a symbol table node. Set up the node's:\n// + type: char, int etc.\n// + ctype: composite type pointer for struct/union\n// + structural type: var, function, array etc.\n// + size: number of elements, or endlabel: end label for a function\n// + posn: Position information for local symbols\n// Return a pointer to the new node.\nstatic struct symtable *newsym(char *name, int type, struct symtable *ctype,\n\t\t\t       int stype, int class, int nelems, int posn) {\n\n  // Get a new node\n  struct symtable *node = (struct symtable *) malloc(sizeof(struct symtable));\n  if (node == NULL)\n    fatal(\"Unable to malloc a symbol table node in newsym\");\n\n  // Fill in the values\n  node->id = Symid++;\n#ifdef DEBUG\n  fprintf(stderr, \"Newsym %s %s id %d\\n\", Sstring[stype], name, node->id);\n#endif\n  if (name == NULL) node->name = NULL;\n  else node->name = strdup(name);\n  node->type = type;\n  node->ctype = ctype;\n  if (ctype != NULL) node->ctypeid = ctype->id;\n  else node->ctypeid = 0;\n  node->stype = stype;\n  node->class = class;\n  node->nelems = nelems;\n  node->st_hasaddr = 0;\n\n  // For pointers and integer types, set the size\n  // of the symbol. structs and union declarations\n  // manually set this up themselves.\n  if (ptrtype(type) || inttype(type))\n    node->size = nelems * typesize(type, ctype);\n\n  node->st_posn = posn;\n  node->next = NULL;\n  node->member = NULL;\n  node->initlist = NULL;\n  return (node);\n}\n\n// Add a new type to the list of types. Return a pointer to the symbol.\nstruct symtable *addtype(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym;\n  thisSym = sym = newsym(name, type, ctype, stype, class, nelems, posn);\n\n#ifdef DEBUG\n  fprintf(stderr, \"Added %s %s to Typelist\\n\",\n\t  Sstring[sym->stype], sym->name);\n#endif\n  appendSym(&Typehead, &Typetail, sym);\n  Membhead = Membtail = NULL;\n  return (sym);\n}\n\n// Add a new symbol to the global table. Return a pointer to the symbol.\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t int stype, int class, int nelems, int posn) {\n  struct symtable *sym;\n  thisSym = sym = newsym(name, type, ctype, stype, class, nelems, posn);\n\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION) sym->size = ctype->size;\n\n#ifdef DEBUG\n  fprintf(stderr, \"Added %s %s to Symlist\\n\", Sstring[sym->stype], sym->name);\n#endif\n  appendSym(&Symhead, &Symtail, sym);\n  Membhead = Membtail = NULL;\n  return (sym);\n}\n\n// Add a symbol to the member list in thisSym\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t int class, int stype, int nelems) {\n  struct symtable *sym = newsym(name, type, ctype, stype, class, nelems, 0);\n\n  // For structs and unions, copy the size from the type node\n  if (type == P_STRUCT || type == P_UNION) sym->size = ctype->size;\n\n  // Add this to the member list and link into thisSym if needed\n  appendSym(&Membhead, &Membtail, sym);\n#ifdef DEBUG\n  fprintf(stderr, \"Added %s %s to Memblist\\n\",\n\t  Sstring[sym->stype], sym->name);\n#endif\n  if (thisSym->member == NULL) {\n    thisSym->member = Membhead;\n#ifdef DEBUG\n    fprintf(stderr, \"Added %s to start of %s\\n\", name, thisSym->name);\n#endif\n  }\n  return (sym);\n}\n\n// Flush the contents of the in-memory symbol tables\n// to the file.\n\nvoid flushSymtable() {\n  struct symtable *this;\n\n  // Write out types\n  for (this = Typehead; this != NULL; this = this->next) {\n    serialiseSym(this);\n  }\n\n  // Write out variables and functions.\n  // Skip invalid symbols\n  for (this = Symhead; this != NULL; this = this->next) {\n    serialiseSym(this);\n  }\n\n  skipSymid = highestSymid;\n  freeSymtable();\n}\n#endif // WRITESYMS\n\n// When reading in globals that have members (structs, unions,\n// functions), we stop once we hit a non-member. We need to\n// record that symbol's offset so we can fseek() back to that.\n// Otherwise we would not be able to load it if it also was a global.\nstatic long lastSymOffset;\n\n// We need a linked list when loadSym() loads in members of a symbol\n// from the disk. We can't use Membhead/tail as this might be in use\n// when parsing the body of a function. So we keep a private list.\nstatic struct symtable *Mhead, *Mtail;\n\n// Given a pointer to a symtable node, read in the next entry\n// in the on-disk symbol table. Do this always if loadit is true.\n// Only read one node if recurse is zero.\n// If loadit is false, load the data and return true if the symbol\n// a) matches the given name and stype or b) matches the id.\n// Return -1 when there is nothing left to read.\nstatic int loadSym(struct symtable *sym, char *name,\n\t\t   int stype, int id, int loadit, int recurse) {\n  struct symtable *memb;\n\n#ifdef DEBUGTOOMUCH\nif (name!=NULL)\n  fprintf(stderr, \"loadSym: name %s stype %d loadit %d recurse %d\\n\",\n\t\tname, stype, loadit, recurse);\nelse\n  fprintf(stderr, \"loadSym: id %d stype %d loadit %d recurse %d\\n\",\n\t\tid, stype, loadit, recurse);\n#endif\n\n  // Read in the next node. Get a copy of the offset beforehand\n  lastSymOffset = ftell(Symfile);\n  if (fread(sym, sizeof(struct symtable), 1, Symfile) != 1) return (-1);\n\n  // Get the symbol name into a separate buffer for now\n  if (sym->name != NULL) {\n    fgetstr(SymText, TEXTLEN + 1, Symfile);\n  }\n\n#ifdef DEBUG\n  if (sym->name != NULL)\n    fprintf(stderr, \"symoff %ld name %s stype %d\\n\",\n\t\tlastSymOffset, SymText, sym->stype);\n  else\n    fprintf(stderr, \"symoff %ld id %d\\n\", lastSymOffset, sym->id);\n#endif\n\n  // If loadit is off, see if the ids match. Or,\n  // see if the names are a match and the stype matches.\n  // For the latter, if NOTATYPE match anything which isn't\n  // a type and which isn't a member, local or param: we are\n  // trying to find a variable, enumval or function. findlocl()\n  // will find it if it's a local or parameter. We only get\n  // here when we are trying to find a global variable,\n  // enumval or function.\n  if (loadit == 0) {\n    if (id != 0 && sym->id == id) loadit = 1;\n    if (name != NULL && !strcmp(name, SymText)) {\n      if (stype == S_NOTATYPE && sym->stype < S_STRUCT\n\t  \t\t      && sym->class < V_LOCAL) loadit = 1;\n      if (stype >= S_STRUCT && stype == sym->stype) loadit = 1;\n    }\n  }\n\n  // Yes, we need to load the rest of the symbol\n  if (loadit) {\n\n    // Copy the name over.\n    sym->name = strdup(SymText);\n    if (sym->name == NULL) fatal(\"Unable to malloc name in loadSym()\");\n\n#ifdef DEBUG\n    if (sym->name == NULL) {\n      fprintf(stderr, \"loadSym found %s NONAME id %d loadit %d\\n\",\n\t      Sstring[sym->stype], sym->id, loadit);\n    } else {\n      fprintf(stderr, \"loadSym found %s %s id %d loadit %d\\n\",\n\t      Sstring[sym->stype], sym->name, sym->id, loadit);\n    }\n#endif\n\n    // Get the initialisation list.\n    if (sym->initlist != NULL) {\n      sym->initlist = (int *) malloc(sym->nelems * sizeof(int));\n      if (sym->initlist == NULL)\n\tfatal(\"Unable to malloc initlist in loadSym()\");\n      fread(sym->initlist, sizeof(int), sym->nelems, Symfile);\n    }\n\n    // Stop now if we must not recursively load more nodes\n    if (!recurse) {\n#ifdef DEBUG\n      fprintf(stderr, \"loadSym found it - no recursion\\n\");\n#endif\n      return (1);\n    }\n\n    // For structs, unions and functions load and add\n    // the members (or params/locals) to the member list\n    if (sym->stype == S_STRUCT || sym->stype == S_UNION\n\t\t\t       || sym->stype == S_FUNCTION) {\n      Mhead = Mtail = NULL;\n\n      while (1) {\n#ifdef DEBUG\nfprintf(stderr, \"loadSym: about to try loading members\\n\");\n#endif\n\tmemb = (struct symtable *) malloc(sizeof(struct symtable));\n\tif (memb == NULL)\n\t  fatal(\"Unable to malloc member in loadSym()\");\n#ifdef MEMBDEBUG\nfprintf(stderr, \"%p allocated\\n\", memb);\n#endif\n\t// Get the next symbol. Stop when there are no symbols\n\t// or when the symbol isn't a member, enumval, param or local\n\tif (loadSym(memb, NULL, 0, 0, 1, 0) != 1)\n\t  break;\n\tif (memb->class != V_LOCAL && memb->class != V_PARAM &&\n\t    memb->class != V_MEMBER)\n\t  break;\n#ifdef DEBUG\nfprintf(stderr, \"loadSym: appending %s to member list\\n\", memb->name);\n#endif\n\tappendSym(&Mhead, &Mtail, memb);\n      }\n\n      // We found a non-member symbol. Seek back\n      // to where it was and free the unused struct.\n      // Attach the member list to the original symbol.\n      fseek(Symfile, lastSymOffset, SEEK_SET);\n#ifdef DEBUG\nfprintf(stderr, \"Seeked to lastSymOffset %ld as non-member id %d\\n\",\n\t\t\t\tlastSymOffset, memb->id);\n#endif\n#ifdef MEMBDEBUG\nfprintf(stderr, \"%p freed, unused memb\\n\", memb);\n#endif\n      free(memb);\n      sym->member = Mhead;\n      Mhead = Mtail = NULL;\n    }\n    return (1);\n  } else {\n    // No match and loadit was 0. Skip over any initialisation list.\n    if (sym->initlist != NULL)\n      fseek(Symfile, sizeof(int) * sym->nelems, SEEK_CUR);\n  }\n  return (0);\n}\n\n// Given a name or an id, search the symbol table file for the next\n// symbol that matches. Fill in the node and return true on a match.\n// Otherwise, return false.\nstatic int findSyminfile(struct symtable *sym, char *name, int id, int stype) {\n  int res;\n\n#ifdef DEBUG\nif (name!=NULL)\n  fprintf(stderr, \"findSyminfile: searching name %s stype %d\\n\", name, stype);\nelse\n  fprintf(stderr, \"findSyminfile: search id %d\\n\", id);\n#endif\n\n  // Loop over the file starting at the beginning\n  fseek(Symfile, 0, SEEK_SET);\n  while (1) {\n    // Does the next symbol match? Yes, return it\n    res = loadSym(sym, name, stype, id, 0, 1);\n    if (res == 1) return (1);\n    if (res == -1) break;\n  }\n#ifdef DEBUG\n  fprintf(stderr, \"findSyminfile: not found\\n\");\n#endif\n  return (0);\n}\n\n// Determine if the symbol name, or id if not zero, is a local\n// or parameter. Return a pointer to the found node or NULL if not found.\nstruct symtable *findlocl(char *name, int id) {\n  struct symtable *this;\n\n  // We must be in a function\n  if (Functionid == NULL) return (NULL);\n\n#ifdef DEBUG\nif (id!=0) fprintf(stderr, \"findlocl() searching for id %d\\n\", id);\nif (name!=NULL) fprintf(stderr, \"findlocl() searching for name %s\\n\", name);\n#endif\n\n  for (this = Functionid->member; this != NULL; this = this->next) {\n    if (id && this->id == id) return (this);\n    if (name && !strcmp(this->name, name)) return (this);\n  }\n\n  return (NULL);\n}\n\n// Given a name and a stype, search for a matching symbol.\n// Or, if the id is non-zero, search for the symbol with that id.\n// Bring the symbol in to one of the in-memory lists if necessary.\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findSymbol(char *name, int stype, int id) {\n  struct symtable *this;\n  struct symtable *sym;\n  int notatype;\n\n  // Set a flag if we are not looking for a type\n  notatype = (stype == S_NOTATYPE || stype == S_ENUMVAL);\n\n#ifdef DEBUG\n  if (id != 0)\n    fprintf(stderr, \"Searching for symbol id %d in memory\\n\", id);\n  else\n    fprintf(stderr, \"Searching for symbol %s %s in memory\\n\",\n\t    Sstring[stype], name);\n#endif\n\n  // If it's not a type, see if\n  // it's a local or parameter\n  if (id || notatype) {\n    this = findlocl(name, id);\n    if (this != NULL) return (this);\n\n#ifdef DEBUG\nfprintf(stderr, \"Not in local, try the global Symlist\\n\");\n#endif\n\n    // Not a local, so search the global symbol list.\n    for (this = Symhead; this != NULL; this = this->next) {\n      if (id && this->id == id) return (this);\n      if (name && !strcmp(this->name, name)) return (this);\n    }\n  }\n\n#ifdef DEBUG\nfprintf(stderr, \"Not in , try the global Typelist\\n\");\n#endif\n\n  // We have an id or it is a type,\n  // Search the global type list.\n  // Sorry for the double negative :-)\n  if (id || !notatype) {\n    for (this = Typehead; this != NULL; this = this->next) {\n      if (id && this->id == id) return (this);\n      if (name && !strcmp(this->name, name) && this->stype == stype)\n\treturn (this);\n    }\n  }\n\n#ifdef DEBUG\n  fprintf(stderr, \"  not in memory, try the file\\n\");\n#endif\n\n  // Not in memory. Try the on-disk symbol table\n  sym = (struct symtable *) malloc(sizeof(struct symtable));\n  if (sym == NULL) {\n    fatal(\"Unable to malloc sym in findSyminlist()\");\n  }\n\n  // If we found a match in the file\n  if (findSyminfile(sym, name, id, stype)) {\n    // Add it to one of the in-memory lists and return it\n    if (sym->stype < S_STRUCT)\n      appendSym(&Symhead, &Symtail, sym);\n    else\n      appendSym(&Typehead, &Typetail, sym);\n\n    // If the symbol points at a composite type, find and link it\n    if (sym->ctype != NULL) {\n#ifdef DEBUG\n      fprintf(stderr, \"About to findSymid on id %d for %s\\n\", sym->ctypeid,\n\t      sym->name);\n#endif\n      sym->ctype = findSymbol(NULL, 0, sym->ctypeid);\n    }\n\n    // If any member symbols point at a composite type, ditto\n    for (this = sym->member; this != NULL; this = this->next)\n      if (this->ctype != NULL) {\n#ifdef DEBUG\n\tfprintf(stderr, \"About to member findSymid on id %d for %s\\n\",\n\t\tthis->ctypeid, this->name);\n#endif\n\tthis->ctype = findSymbol(NULL, 0, this->ctypeid);\n      }\n    return (sym);\n  }\n  free(sym);\n  return (NULL);\n}\n\n// Find a member in the member list. Return a pointer\n// to the found node or NULL if not found.\nstruct symtable *findmember(char *s) {\n  struct symtable *node;\n\n  for (node = Membhead; node != NULL; node = node->next)\n    if (!strcmp(s, node->name)) return (node);\n\n  return (NULL);\n}\n\n// Find a node in the struct list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findstruct(char *s) {\n  return (findSymbol(s, S_STRUCT, 0));\n}\n\n// Find a node in the union list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findunion(char *s) {\n  return (findSymbol(s, S_UNION, 0));\n}\n\n// Find an enum type in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumtype(char *s) {\n  return (findSymbol(s, S_ENUMTYPE, 0));\n}\n\n// Find an enum value in the enum list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findenumval(char *s) {\n  return (findSymbol(s, S_ENUMVAL, 0));\n}\n\n// Find a type in the tyedef list\n// Return a pointer to the found node or NULL if not found.\nstruct symtable *findtypedef(char *s) {\n  return (findSymbol(s, S_TYPEDEF, 0));\n}\n\n// Free a symbol's memory, returning the symbol's next pointer\nstruct symtable *freeSym(struct symtable *sym) {\n  struct symtable *next, *memb;\n\n  if (sym == NULL) return (NULL);\n  next = sym->next;\n#ifdef MEMBDEBUG\n  fprintf(stderr, \"%p freeing\\n\", sym);\n#endif\n#ifdef DEBUG\n  fprintf(stderr, \"Freeing %s %s\\n\", Sstring[sym->stype], sym->name);\n#endif\n\n  // Free any members\n  for (memb = sym->member; memb != NULL;)\n    memb = freeSym(memb);\n\n  // Free the initlist and the name\n  if (sym->initlist != NULL)\n    free(sym->initlist);\n  if (sym->name != NULL)\n    free(sym->name);\n  free(sym);\n  return (next);\n}\n\n// Free the contents of the in-memory symbol tables\nvoid freeSymtable() {\n  struct symtable *this;\n\n  for (this = Symhead; this != NULL;)\n    this = freeSym(this);\n  for (this = Typehead; this != NULL;)\n    this = freeSym(this);\n  Symhead = Symtail = Typehead = Typetail = NULL;\n  Membhead = Membtail = Functionid = NULL;\n}\n\n// Loop over the symbol table file.\n// Load in all the types and\n// global/static variables.\nvoid loadGlobals(void) {\n  struct symtable *sym;\n  int i;\n\n  // Start at the file's beginning. Load all symbols\n  fseek(Symfile, 0, SEEK_SET);\n  while (1) {\n    // Load the next symbol + members + initlist\n    sym = (struct symtable *) malloc(sizeof(struct symtable));\n    if (sym == NULL)\n      fatal(\"Unable to malloc in allocateGlobals()\");\n    i = loadSym(sym, NULL, 0, 0, 1, 1);\n    if (i == -1) {\n      free(sym); break;\n    }\n\n    // Add any type to the type list\n    if (sym->stype >= S_STRUCT) {\n      appendSym(&Typehead, &Typetail, sym); continue;\n    }\n\n    // Add any global/static variable/array/strlit to the sym list\n    if ((sym->class == V_GLOBAL || sym->class == V_STATIC) &&\n\t(sym->stype == S_VARIABLE || sym->stype == S_ARRAY ||\n\t sym->stype == S_STRLIT)) {\n      appendSym(&Symhead, &Symtail, sym);\n\n      // If the symbol points at a composite type, find and link it\n      if (sym->ctype != NULL) {\n\tsym->ctype = findSymbol(NULL, 0, sym->ctypeid);\n      }\n      continue;\n    }\n\n    // Didn't add it to any list\n    freeSym(sym);\n  }\n}\n"
  },
  {
    "path": "64_6809_Target/sym.h",
    "content": "// sym.c\nstruct symtable *addtype(char *name, int type, struct symtable *ctype,\n\t\t\t\tint stype, int class, int nelems, int posn);\nstruct symtable *addglob(char *name, int type, struct symtable *ctype,\n\t\t\t\tint stype, int class, int nelems, int posn);\nstruct symtable *addmemb(char *name, int type, struct symtable *ctype,\n\t\t\t\t          int class, int stype, int nelems);\nstruct symtable *findlocl(char *name, int id);\nstruct symtable *findSymbol(char *name, int stype, int id);\nstruct symtable *findmember(char *s);\nstruct symtable *findstruct(char *s);\nstruct symtable *findunion(char *s);\nstruct symtable *findenumtype(char *s);\nstruct symtable *findenumval(char *s);\nstruct symtable *findtypedef(char *s);\nvoid loadGlobals(void);\nstruct symtable *freeSym(struct symtable *sym);\nvoid freeSymtable(void);\nvoid flushSymtable(void);\nvoid dumpSymlists(void);\n\nextern struct symtable *Symhead;\n"
  },
  {
    "path": "64_6809_Target/targ6809.c",
    "content": "#include \"defs.h\"\n#include \"misc.h\"\n#include \"types.h\"\n\n// Target-specific functions which get used\n// by the parser as well as the code generator.\n// Copyright (c) 2024 Warren Toomey, GPL3\n\n// Given a scalar type value, return the\n// size of the type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (2);\n  switch (type) {\n  case P_VOID:\n    return (0);\n  case P_CHAR:\n    return (1);\n  case P_INT:\n    return (2);\n  case P_LONG:\n    return (4);\n  default:\n    fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);                   // Keep -Wall happy\n}\n\nint cgalign(int type, int offset, int direction) {\n  return (offset);\n}\n\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n\n// Return the primitive type that can hold an address.\n// This is used when we need to add a INTLIT to a\n// pointer.\nint cgaddrint(void) {\n  return(P_INT);\n}\n"
  },
  {
    "path": "64_6809_Target/target.h",
    "content": "/* target.c */\nint cgprimsize(int type);\nint cgalign(int type, int offset, int direction);\nint genprimsize(int type);\nint genalign(int type, int offset, int direction);\nint cgaddrint(void);\n"
  },
  {
    "path": "64_6809_Target/targqbe.c",
    "content": "#include \"defs.h\"\n#include \"misc.h\"\n#include \"types.h\"\n\n// Target-specific functions which get used\n// by the parser as well as the code generator.\n// Copyright (c) 2024 Warren Toomey, GPL3\n\n// Given a scalar type value, return the\n// size of the QBE type in bytes.\nint cgprimsize(int type) {\n  if (ptrtype(type))\n    return (8);\n  switch (type) {\n    case P_CHAR:\n      return (1);\n    case P_INT:\n      return (4);\n    case P_LONG:\n      return (8);\n    default:\n      fatald(\"Bad type in cgprimsize:\", type);\n  }\n  return (0);                   // Keep -Wall happy\n}\n\n// Given a scalar type, an existing memory offset\n// (which hasn't been allocated to anything yet)\n// and a direction (1 is up, -1 is down), calculate\n// and return a suitably aligned memory offset\n// for this scalar type. This could be the original\n// offset, or it could be above/below the original\nint cgalign(int type, int offset, int direction) {\n  int alignment;\n\n  // We don't need to do this on x86-64, but let's\n  // align chars on any offset and align ints/pointers\n  // on a 4-byte alignment\n  switch (type) {\n    case P_CHAR:\n      break;\n    default:\n      // Align whatever we have now on a 4-byte alignment.\n      // I put the generic code here so it can be reused elsewhere.\n      alignment = 4;\n      offset = (offset + direction * (alignment - 1)) & ~(alignment - 1);\n  }\n  return (offset);\n}\n\nint genprimsize(int type) {\n  return (cgprimsize(type));\n}\n\nint genalign(int type, int offset, int direction) {\n  return (cgalign(type, offset, direction));\n}\n\n\n// Return the primitive type that can hold an address.\n// This is used when we need to add a INTLIT to a\n// pointer.\nint cgaddrint(void) {\n  return(P_LONG);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/Makefile",
    "content": "clean:\n\trm -f *_* input??? trial.input058.c\n\trm -rf *.o *.s *.map *_*\n"
  },
  {
    "path": "64_6809_Target/tests/err.input031.c",
    "content": "Expecting a primary expression, got token:+ on line 5 of input031.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input032.c",
    "content": "Unknown variable or function:pizza on line 4 of input032.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input033.c",
    "content": "Incompatible type to return on line 4 of input033.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input034.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 4 of input034.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input035.c",
    "content": "Duplicate local variable declaration:a on line 4 of input035.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input036.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input036.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input037.c",
    "content": "Expected:comma on line 3 of input037.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input038.c",
    "content": "Type doesn't match prototype for parameter:2 on line 4 of input038.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input039.c",
    "content": "No statements in function with non-void type on line 4 of input039.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input041.c",
    "content": "Can't return from a void function on line 3 of input041.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input042.c",
    "content": "Unknown variable or function:fred on line 3 of input042.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input043.c",
    "content": "Unknown variable or function:b on line 3 of input043.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input044.c",
    "content": "Unknown variable or function:z on line 3 of input044.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input045.c",
    "content": "& operator must be followed by an identifier on line 3 of input045.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input046.c",
    "content": "* operator must be followed by an expression of pointer type on line 3 of input046.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input047.c",
    "content": "++ operator must be followed by an identifier on line 3 of input047.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input048.c",
    "content": "-- operator must be followed by an identifier on line 3 of input048.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input049.c",
    "content": "Incompatible expression in assignment on line 6 of input049.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input050.c",
    "content": "Incompatible types in binary expression on line 6 of input050.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input051.c",
    "content": "Expected '\\'' at end of char literal on line 4 of input051.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input052.c",
    "content": "Unrecognised character:$ on line 5 of input052.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input056.c",
    "content": "unknown struct/union type:var1 on line 2 of input056.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input057.c",
    "content": "previously defined struct/union:fred on line 2 of input057.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input059.c",
    "content": "Unknown variable or function:y on line 3 of input059.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input060.c",
    "content": "Expression is not a struct/union on line 3 of input060.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input061.c",
    "content": "Expression is not a pointer to a struct/union on line 3 of input061.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input064.c",
    "content": "undeclared enum type::fred on line 1 of input064.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input065.c",
    "content": "enum type redeclared::fred on line 2 of input065.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input066.c",
    "content": "enum value redeclared::z on line 2 of input066.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input068.c",
    "content": "redefinition of typedef:FOO on line 2 of input068.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input069.c",
    "content": "unknown type:FLOO on line 2 of input069.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input072.c",
    "content": "no loop or switch to break out from on line 1 of input072.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input073.c",
    "content": "no loop to continue to on line 1 of input073.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input075.c",
    "content": "Unexpected token in switch:if on line 4 of input075.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input076.c",
    "content": "No cases in switch on line 3 of input076.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input077.c",
    "content": "case or default after existing default on line 6 of input077.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input078.c",
    "content": "case or default after existing default on line 6 of input078.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input079.c",
    "content": "Duplicate case value on line 6 of input079.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input085.c",
    "content": "Bad type in parameter list on line 1 of input085.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input086.c",
    "content": "Function definition not at global level on line 3 of input086.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input087.c",
    "content": "Bad type in member list on line 4 of input087.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input092.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input092.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input093.c",
    "content": "Unknown variable or function:fred on line 1 of input093.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input094.c",
    "content": "Type mismatch: literal vs. variable on line 1 of input094.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input095.c",
    "content": "Variable can not be initialised:x on line 1 of input095.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input096.c",
    "content": "Array size is illegal:0 on line 1 of input096.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input097.c",
    "content": "For now, declaration of non-global arrays is not implemented on line 2 of input097.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input098.c",
    "content": "Too many values in initialisation list on line 1 of input098.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input102.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input102.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input103.c",
    "content": "Cannot cast to a struct, union or void type on line 3 of input103.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input104.c",
    "content": "Cannot cast to a struct, union or void type on line 2 of input104.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input105.c",
    "content": "Incompatible expression in assignment on line 4 of input105.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input118.c",
    "content": "Compiler doesn't support static or extern local declarations on line 2 of input118.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input124.c",
    "content": "Cannot ++ on rvalue on line 6 of input124.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input126.c",
    "content": "Unknown variable or function:ptr on line 7 of input126.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input129.c",
    "content": "Cannot ++ and/or -- more than once on line 6 of input129.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input141.c",
    "content": "Declaration of array parameters is not implemented on line 4 of input141.c\n"
  },
  {
    "path": "64_6809_Target/tests/err.input142.c",
    "content": "Array must have non-zero elements:fred on line 1 of input142.c\n"
  },
  {
    "path": "64_6809_Target/tests/input.rules.6809",
    "content": "# Test file for the peephole optimiser\n#1\n\taddd #0\n#2\n\tleas -0,s\n#3\n\tleas 0,s\n#4\n\tstd _a\n\tldd _a\n#5\n\tstd _a\n;\n\tldd _a\n#6\n\tstd _a\n;\n;\n\tldd _a\n#7\n\tstb _a\n\tldb _a\n#8\n\tstb _a\n;\n\tldb _a\n#9\n\tstb _a\n;\n;\n\tldb _a\n#10\n\tstd R0\n\tldd _a\n\taddd R0\n#11\n\tldx 6,s\n\tldd 0,x\n#12\n\tldx 7,s\n\tstb 0,x\n#13\n\tldx 6,s\n\tldb 0,x\n#14\n\tldx 7,s\n\tstd 0,x\n#15\n\tldx 3,s\n\tldd #15\n\tstd 0,x\n#16\n\tldd _a\n\ttfr d,x\n#17\n\tbra L5\n;\nL5:\n#18\n\tbra L9\nL9:\n#19\n\ttfr x,d\n\tstd _b\n#20\n\tldx #_fred\n\tldd _jim\n\tstd 0,x\n#21\n\tldd #_fred\n\taddd #4\n\ttfr d,x\n\tldd _b\n\tstd 0,x\n#22\n\tldx #_fred\n\tldd 0,x\n#23\n\tldd #_fred\n\taddd #4\n\ttfr d,x\n\tldd 0,x\n#24\n\tldd 4,s\n\taddd #14\n\ttfr d,x\n\tldd R0+0\n\tstd 0,x\n#25\n\tldd 4,s\n\taddd #8\n\ttfr d,x\n\tldd 0,x\n#26\n\tldd 0,s\n\tpshs d\n\tldd #1\n\tlbsr __shl\n\tstd 0,s\n"
  },
  {
    "path": "64_6809_Target/tests/input001.c",
    "content": "int printf(char *fmt, ...);\n\nvoid main()\n{ printf(\"%d\\n\", 12 * 3);\n  printf(\"%d\\n\", 18 - 2 * 4);\n  printf(\"%d\\n\", 1 + 2 + 9 - 5/2 + 3*5);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input002.c",
    "content": "int printf(char *fmt, ...);\n\nvoid main()\n{\n  int fred;\n  int jim;\n  fred= 5;\n  jim= 12;\n  printf(\"%d\\n\", fred + jim);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input003.c",
    "content": "int printf(char *fmt, ...);\n\nvoid main()\n{\n  int x;\n  x= 1;     printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n  x= x + 1; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input004.c",
    "content": "int printf(char *fmt, ...);\n\nvoid main()\n{\n  int x;\n  x= 7 < 9;  printf(\"%d\\n\", x);\n  x= 7 <= 9; printf(\"%d\\n\", x);\n  x= 7 != 9; printf(\"%d\\n\", x);\n  x= 7 == 7; printf(\"%d\\n\", x);\n  x= 7 >= 7; printf(\"%d\\n\", x);\n  x= 7 <= 7; printf(\"%d\\n\", x);\n  x= 9 > 7;  printf(\"%d\\n\", x);\n  x= 9 >= 7; printf(\"%d\\n\", x);\n  x= 9 != 7; printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input005.c",
    "content": "int printf(char *fmt, ...);\n\nvoid main()\n{\n  int i; int j;\n  i=6; j=12;\n  if (i < j) {\n    printf(\"%d\\n\", i);\n  } else {\n    printf(\"%d\\n\", j);\n  }\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input006.c",
    "content": "int printf(char *fmt, ...);\n\nvoid main()\n{ int i;\n  i=1;\n  while (i <= 10) {\n    printf(\"%d\\n\", i);\n    i= i + 1;\n  }\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input007.c",
    "content": "int printf(char *fmt, ...);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input008.c",
    "content": "int printf(char *fmt, ...);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input009.c",
    "content": "int printf(char *fmt, ...);\n\nvoid main()\n{\n  int i;\n  for (i= 1; i <= 10; i= i + 1) {\n    printf(\"%d\\n\", i);\n  }\n}\n\nvoid fred()\n{\n  int a; int b;\n  a= 12; b= 3 * a;\n  if (a >= b) { printf(\"%d\\n\", 2 * b - a); }\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input010.c",
    "content": "int printf(char *fmt, ...);\n\nvoid main()\n{\n  int i; char j;\n\n  j= 20; printf(\"%d\\n\", j);\n  i= 10; printf(\"%d\\n\", i);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 2; j= j + 1) { printf(\"%d\\n\", j); }\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input011.c",
    "content": "int printf(char *fmt, ...);\n\nint main()\n{\n  int i; char j; long k;\n\n  i= 10; printf(\"%d\\n\", i);\n  j= 20; printf(\"%d\\n\", j);\n  k= 30; printf(\"%ld\\n\", k);\n\n  for (i= 1;   i <= 5; i= i + 1) { printf(\"%d\\n\", i); }\n  for (j= 253; j != 4; j= j + 1) { printf(\"%d\\n\", j); }\n  for (k= 1;   k <= 5; k= k + 1) { printf(\"%ld\\n\", k); }\n  return(i);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input012.c",
    "content": "int printf(char *fmt, ...);\n\nint fred(int x) {\n  return(5);\n}\n\nvoid main() {\n  int x;\n  x= fred(2);\n  printf(\"%d\\n\", x);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input013.c",
    "content": "int printf(char *fmt, ...);\n\nint fred(int x) {\n  return(56);\n}\n\nvoid main() {\n  int dummy;\n  int result;\n  dummy= printf(\"%d\\n\", 23);\n  result= fred(10);\n  dummy= printf(\"%d\\n\", result);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input014.c",
    "content": "int printf(char *fmt, ...);\n\nint fred(int x) {\n  return(20);\n}\n\nint main() {\n  int result;\n  printf(\"%d\\n\", 10);\n  result= fred(15);\n  printf(\"%d\\n\", result);\n  printf(\"%d\\n\", fred(15)+10);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input015.c",
    "content": "int printf(char *fmt, ...);\n\nint main() {\n  char  a;\n  char *b;\n  char  c;\n\n  int   d;\n  int  *e;\n  int   f;\n\n  a= 18; printf(\"%d\\n\", a);\n  b= &a; c= *b; printf(\"%d\\n\", c);\n\n  d= 12; printf(\"%d\\n\", d);\n  e= &d; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input016.c",
    "content": "int printf(char *fmt, ...);\n\nint   c;\nint   d;\nint  *e;\nint   f;\n\nint main() {\n  c= 12; d=18; printf(\"%d\\n\", c);\n  e= &c + 1; f= *e; printf(\"%d\\n\", f);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input017.c",
    "content": "int printf(char *fmt, ...);\n\nint main() {\n  char  a;\n  char *b;\n  int   d;\n  int  *e;\n\n  b= &a; *b= 19; printf(\"%d\\n\", a);\n  e= &d; *e= 12; printf(\"%d\\n\", d);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input018.c",
    "content": "int printf(char *fmt, ...);\n\nint main()\n{\n  int a;\n  int b;\n  a= b= 34;\n  printf(\"%d\\n\", a);\n  printf(\"%d\\n\", b);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input018a.c",
    "content": "int printf(char *fmt, ...);\n\nint   a;\nint  *b;\nchar  c;\nchar *d;\n\nint main()\n{\n  b= &a; *b= 15; printf(\"%d\\n\", a);\n  d= &c; *d= 16; printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input019.c",
    "content": "int printf(char *fmt, ...);\n\nint a;\nint b;\nint c;\nint d;\nint e;\nint main()\n{\n  a= 2; b= 4; c= 3; d= 2;\n  e= (a+b) * (c+d);\n  printf(\"%d\\n\", e);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input020.c",
    "content": "int printf(char *fmt, ...);\n\nint a;\nint b[25];\n\nint main() {\n  b[3]= 12;\n  a= b[3];\n  printf(\"%d\\n\", a);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input021.c",
    "content": "int printf(char *fmt, ...);\n\nchar  c;\nchar *str;\n\nint main() {\n  c= '\\n'; printf(\"%d\\n\", c);\n\n  for (str= \"Hello world\\n\"; *str != 0; str= str + 1) {\n    printf(\"%c\", *str);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input022.c",
    "content": "int printf(char *fmt, ...);\n\nchar a; char b; char c;\nint  d; int  e; int  f;\nlong g; long h; long i;\n\n\nint main() {\n  b= 5; c= 7; a= b + c++; printf(\"%d\\n\", a);\n  e= 5; f= 7; d= e + f++; printf(\"%d\\n\", d);\n  h= 5; i= 7; g= h + i++; printf(\"%ld\\n\", g);\n  a= b-- + c; printf(\"%d\\n\", a);\n  d= e-- + f; printf(\"%d\\n\", d);\n  g= h-- + i; printf(\"%ld\\n\", g);\n  a= ++b + c; printf(\"%d\\n\", a);\n  d= ++e + f; printf(\"%d\\n\", d);\n  g= ++h + i; printf(\"%ld\\n\", g);\n  a= b * --c; printf(\"%d\\n\", a);\n  d= e * --f; printf(\"%d\\n\", d);\n  g= h * --i; printf(\"%ld\\n\", g);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input023.c",
    "content": "int printf(char *fmt, ...);\n\nchar *str;\nint   x;\n\nint main() {\n  x= -23; printf(\"%d\\n\", x);\n  printf(\"%d\\n\", -10 * -10);\n\n  x= 1; x= ~x; printf(\"%d\\n\", x);\n\n  x= 2 > 5; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n  x= !x; printf(\"%d\\n\", x);\n\n  x= 13; if (x) { printf(\"%d\\n\", 13); }\n  x= 0; if (!x) { printf(\"%d\\n\", 14); }\n\n  for (str= \"Hello world\\n\"; *str; str++) {\n    printf(\"%c\", *str);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input024.c",
    "content": "int printf(char *fmt, ...);\n\nint a;\nint b;\nint c;\nint main() {\n  a= 42; b= 19;\n  printf(\"%d\\n\", a & b);\n  printf(\"%d\\n\", a | b);\n  printf(\"%d\\n\", a ^ b);\n  printf(\"%d\\n\", 1 << 3);\n  printf(\"%d\\n\", 63 >> 3);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input025.c",
    "content": "int printf(char *fmt, ...);\n\nint a;\nint b;\nint c;\n\nint main()\n{\n  char z;\n  int y;\n  int x;\n  x= 10; y= 20; z= 30;\n  printf(\"%d\\n\", x); printf(\"%d\\n\", y); printf(\"%d\\n\", z);\n  a= 5; b= 15; c= 25;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input026.c",
    "content": "int printf(char *fmt, ...);\n\nint main(int a, char b, long c, int d, int e, int f, int g, int h) {\n  int i; int j; int k;\n\n  a= 13; printf(\"%d\\n\", a);\n  b= 23; printf(\"%d\\n\", b);\n  c= 34; printf(\"%ld\\n\", c);\n  d= 44; printf(\"%d\\n\", d);\n  e= 54; printf(\"%d\\n\", e);\n  f= 64; printf(\"%d\\n\", f);\n  g= 74; printf(\"%d\\n\", g);\n  h= 84; printf(\"%d\\n\", h);\n  i= 94; printf(\"%d\\n\", i);\n  j= 95; printf(\"%d\\n\", j);\n  k= 96; printf(\"%d\\n\", k);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input027.c",
    "content": "int printf(char *fmt, ...);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint param5(int a, int b, int c, int d, int e) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param2(int a, int b) {\n  int c; int d; int e;\n  c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint param0() {\n  int a; int b; int c; int d; int e;\n  a= 1; b= 2; c= 3; d= 4; e= 5;\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d); printf(\"%d\\n\", e);\n  return(0);\n}\n\nint main() {\n  param8(1,2,3,4,5,6,7,8);\n  param5(1,2,3,4,5);\n  param2(1,2);\n  param0();\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input028.c",
    "content": "int printf(char *fmt, ...);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input029.c",
    "content": "int printf(char *fmt, ...);\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h);\nint fred(int a, int b, int c);\nint main();\n\nint param8(int a, int b, int c, int d, int e, int f, int g, int h) {\n  printf(\"%d\\n\", a); printf(\"%d\\n\", b); printf(\"%d\\n\", c); printf(\"%d\\n\", d);\n  printf(\"%d\\n\", e); printf(\"%d\\n\", f); printf(\"%d\\n\", g); printf(\"%d\\n\", h);\n  return(0);\n}\n\nint fred(int a, int b, int c) {\n  return(a+b+c);\n}\n\nint main() {\n  int x;\n  param8(1, 2, 3, 5, 8, 13, 21, 34);\n  x= fred(2, 3, 4); printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input030.c",
    "content": "int printf(char *fmt, ...);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input031.c",
    "content": "int printf(char *fmt, ...);\n\nint main() {\n  int x;\n  x= 2 + + 3 - * / ;\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input032.c",
    "content": "int printf(char *fmt, ...);\n\nint main() {\n  pizza cow llama sausage;\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input033.c",
    "content": "int printf(char *fmt, ...);\n\nint main() {\n  char *z; return(z);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input035.c",
    "content": "int printf(char *fmt, ...);\n\nint fred(int a, int b) {\n  int a;\n  return(a);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input036.c",
    "content": "int printf(char *fmt, ...);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c);\n"
  },
  {
    "path": "64_6809_Target/tests/input037.c",
    "content": "int printf(char *fmt, ...);\n\nint fred(int a, char b +, int z);\n"
  },
  {
    "path": "64_6809_Target/tests/input038.c",
    "content": "int printf(char *fmt, ...);\n\nint fred(int a, char b, int c);\nint fred(int a, int b, char c, int g);\n"
  },
  {
    "path": "64_6809_Target/tests/input039.c",
    "content": "int printf(char *fmt, ...);\n\nint main() { int a; }\n"
  },
  {
    "path": "64_6809_Target/tests/input041.c",
    "content": "int printf(char *fmt, ...);\n\nvoid fred() { return(5); }\n"
  },
  {
    "path": "64_6809_Target/tests/input042.c",
    "content": "int printf(char *fmt, ...);\n\nint main() { fred(5); }\n"
  },
  {
    "path": "64_6809_Target/tests/input043.c",
    "content": "int printf(char *fmt, ...);\n\nint main() { int a; a= b[4]; }\n"
  },
  {
    "path": "64_6809_Target/tests/input044.c",
    "content": "int printf(char *fmt, ...);\n\nint main() { int a; a= z; }\n"
  },
  {
    "path": "64_6809_Target/tests/input045.c",
    "content": "int printf(char *fmt, ...);\n\nint main() { int a; a= &5; }\n"
  },
  {
    "path": "64_6809_Target/tests/input046.c",
    "content": "int printf(char *fmt, ...);\n\nint main() { int a; a= *5; }\n"
  },
  {
    "path": "64_6809_Target/tests/input047.c",
    "content": "int printf(char *fmt, ...);\n\nint main() { int a; a= ++5; }\n"
  },
  {
    "path": "64_6809_Target/tests/input048.c",
    "content": "int printf(char *fmt, ...);\n\nint main() { int a; a= --5; }\n"
  },
  {
    "path": "64_6809_Target/tests/input049.c",
    "content": "int printf(char *fmt, ...);\n\nint main() {\n int x;\n char y;\n y= x;\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input050.c",
    "content": "int printf(char *fmt, ...);\n\nint main() {\n char *a;\n char *b;\n a= a + b;\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input051.c",
    "content": "int printf(char *fmt, ...);\n\nint main() {\n  char a; a= 'fred';\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input052.c",
    "content": "int printf(char *fmt, ...);\n\nint main() {\n  int a;\n  a= $5.00;\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input053.c",
    "content": "int printf(char *fmt, ...);\n\nint main()\n{\n  printf(\"Hello world, %d\\n\", 23);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input054.c",
    "content": "int printf(char *fmt, ...);\n\nint main()\n{\n  int i;\n  for (i=0; i < 20; i++) {\n    printf(\"Hello world, %d\\n\", i);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input055.c",
    "content": "int printf(char *fmt, ...);\n\nint main(int argc, char **argv) {\n  int i;\n  char *argument;\n  printf(\"Hello world\\n\");\n\n  for (i=0; i < argc; i++) {\n    argument= *argv; argv= argv + 1;\n    printf(\"Argument %d is %s\\n\", i, argument);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input056.c",
    "content": "struct foo { int x; };\nstruct mary var1;\n"
  },
  {
    "path": "64_6809_Target/tests/input057.c",
    "content": "struct fred { int x;  } ;\nstruct fred { char y; } ;\n"
  },
  {
    "path": "64_6809_Target/tests/input058.c",
    "content": "int printf(char *fmt, ...);\n\nstruct fred {\n  int x;\n  char y;\n  long z;\n};\n\nstruct fred var2;\nstruct fred *varptr;\n\nint main() {\n  long result;\n\n  var2.x= 12;   printf(\"%d\\n\", var2.x);\n  var2.y= 'c';  printf(\"%d\\n\", var2.y);\n  var2.z= 4005; printf(\"%ld\\n\", var2.z);\n\n  result= var2.x + var2.y + var2.z;\n  printf(\"%ld\\n\", result);\n\n  varptr= &var2;\n  result= varptr->x + varptr->y + varptr->z;\n  printf(\"%ld\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input059.c",
    "content": "int main() {\n  int x;\n  x= y.foo;\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input060.c",
    "content": "int main() {\n  int x;\n  x= x.foo;\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input061.c",
    "content": "int main() {\n  int x;\n  x= x->foo;\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input063.c",
    "content": "int printf(char *fmt, ...);\n\nenum fred { apple=1, banana, carrot, pear=10, peach, mango, papaya };\nenum jane { aple=1, bnana, crrot, par=10, pech, mago, paaya };\n\nenum fred var1;\nenum jane var2;\nenum fred var3;\n\nint main() {\n  var1= carrot + pear + mango;\n  printf(\"%d\\n\", var1);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input064.c",
    "content": "enum fred var3;\n"
  },
  {
    "path": "64_6809_Target/tests/input065.c",
    "content": "enum fred { x, y, z };\nenum fred { a, b };\n"
  },
  {
    "path": "64_6809_Target/tests/input066.c",
    "content": "enum fred { x, y, z };\nenum mary { a, b, z };\n"
  },
  {
    "path": "64_6809_Target/tests/input067.c",
    "content": "int printf(char *fmt, ...);\n\ntypedef int FOO;\nFOO var1;\n\nstruct bar { int x; int y} ;\ntypedef struct bar BAR;\nBAR var2;\n\nint main() {\n  var1= 5; printf(\"%d\\n\", var1);\n  var2.x= 7; var2.y= 10; printf(\"%d\\n\", var2.x + var2.y);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input068.c",
    "content": "typedef int FOO;\ntypedef char FOO;\n"
  },
  {
    "path": "64_6809_Target/tests/input069.c",
    "content": "typedef int FOO;\nFLOO y;\n"
  },
  {
    "path": "64_6809_Target/tests/input070.c",
    "content": "#include <stdio.h>\n\ntypedef int FOO;\n\nint main() {\n  FOO x;\n  x= 56;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input071.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  x = 0;\n  while (x < 100) {\n    if (x == 5) { x = x + 2; continue; }\n    printf(\"%d\\n\", x);\n    if (x == 14) { break; }\n    x = x + 1;\n  }\n  printf(\"Done\\n\");\n  return (0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input072.c",
    "content": "int main() { break; }\n"
  },
  {
    "path": "64_6809_Target/tests/input073.c",
    "content": "int main() { continue; }\n"
  },
  {
    "path": "64_6809_Target/tests/input074.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  int y;\n  y= 0;\n\n  for (x=0; x < 5; x++) {\n    switch(x) {\n      case 1:  { y= 5; break; }\n      case 2:  { y= 7; break; }\n      case 3:  { y= 9; }\n      default: { y= 100; }\n    }\n    printf(\"%d\\n\", y);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input075.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    if (x<5);\n  }\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input076.c",
    "content": "int main() {\n  int x;\n  switch(x) { }\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input077.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    case 4: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input078.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    default: { x= 3; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input079.c",
    "content": "int main() {\n  int x;\n  switch(x) {\n    case 1: { x= 2; }\n    case 2: { x= 2; }\n    case 1: { x= 2; }\n    default: { x= 2; }\n  }\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input080.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  for (x=0, y=1; x < 6; x++, y=y+2) {\n    printf(\"%d %d\\n\", x, y);\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input081.c",
    "content": "#include <stdio.h> \n\nint x;\nint y;\n\nint main() {\n\n  x= 0; y=1;\n\n  for (;x<5;) {\n    printf(\"%d %d\\n\", x, y);\n    x=x+1;\n    y=y+2;\n  }\n\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input082.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  x= 10;\n  // Dangling else test\n  if (x > 5)\n    if (x > 15)\n      printf(\"x > 15\\n\");\n    else\n      printf(\"15 >= x > 5\\n\");\n  else\n    printf(\"5 >= x\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input083.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n\n  // Dangling else test.\n  // We should not print anything for x<= 5\n  for (x=0; x < 12; x++)\n    if (x > 5)\n      if (x > 10)\n        printf(\"10 < %2d\\n\", x);\n      else\n        printf(\" 5 < %2d <= 10\\n\", x);\n  return(0);\n}\n\n"
  },
  {
    "path": "64_6809_Target/tests/input084.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x, y;\n  x=2; y=3;\n  printf(\"%d %d\\n\", x, y);\n\n  char a, *b;\n  a= 'f'; b= &a;\n  printf(\"%c %c\\n\", a, *b);\n\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input085.c",
    "content": "int main(struct foo { int x; }; , int a) {\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input086.c",
    "content": "int main() {\n  int fred() { return(5); }\n  int x;\n  x=2;\n  return(x);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input087.c",
    "content": "struct foo {\n  int x;\n  int y;\n  struct blah { int g; };\n};\n"
  },
  {
    "path": "64_6809_Target/tests/input088.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int x;\n  int y;\n} fred, mary;\n\nstruct foo james;\n\nint main() {\n  fred.x= 5;\n  mary.y= 6;\n  printf(\"%d %d\\n\", fred.x, mary.y);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input089.c",
    "content": "#include <stdio.h>\n\nint x= 23;\nchar y= 'H';\nchar *z= \"Hello world\";\n\nint main() {\n  printf(\"%d %c %s\\n\", x, y, z);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input090.c",
    "content": "#include <stdio.h>\n\nint a = 23, b = 100;\nchar y = 'H', *z = \"Hello world\";\n\nint main() {\n  printf(\"%d %d %c %s\\n\", a, b, y, z);\n  return (0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input091.c",
    "content": "#include <stdio.h>\n\nint fred[] = { 1, 2, 3, 4, 5 };\nint jim[10] = { 1, 2, 3, 4, 5 };\n\nint main() {\n  int i;\n  for (i=0; i < 5; i++) printf(\"%d\\n\", fred[i]);\n  for (i=0; i < 10; i++) printf(\"%d\\n\", jim[i]);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input092.c",
    "content": "char x= 3000;\n"
  },
  {
    "path": "64_6809_Target/tests/input093.c",
    "content": "char x= fred;\n"
  },
  {
    "path": "64_6809_Target/tests/input094.c",
    "content": "char *s= 54;\n"
  },
  {
    "path": "64_6809_Target/tests/input095.c",
    "content": "int fred(int x=2) { return(x); }\n"
  },
  {
    "path": "64_6809_Target/tests/input096.c",
    "content": "int fred[0];\n"
  },
  {
    "path": "64_6809_Target/tests/input098.c",
    "content": "int fred[3]= { 1, 2, 3, 4, 5 };\n"
  },
  {
    "path": "64_6809_Target/tests/input099.c",
    "content": "#include <stdio.h>\n\n// List of token strings, for debugging purposes.\n// As yet, we can't store a NULL into the list\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \",\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"\"\n};\n\nint main() {\n  int i;\n  char *str;\n\n  i=0;\n  while (1) {\n    str= Tstring[i];\n    if (*str == 0) break;\n    printf(\"%s\\n\", str);\n    i++;\n  }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input100.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 3, y=14;\n  int z= 2 * x + y;\n  char *str= \"Hello world\";\n  printf(\"%s %d %d\\n\", str, x+y, z);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input101.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x= 65535;\n  char y;\n  char *str;\n\n  y= (char )x; printf(\"0x%x\\n\", y);\n  str= (char *)0; printf(\"0x%lx\\n\", (long)str);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input102.c",
    "content": "int main() {\n  struct foo { int p; };\n  int y= (struct foo) x;\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input103.c",
    "content": "int main() {\n  union foo { int p; };\n  int y= (union foo) x;\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input104.c",
    "content": "int main() {\n  int y= (void) x;\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input105.c",
    "content": "int main() {\n  int x;\n  char *y;\n  y= (char) x;\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input106.c",
    "content": "#include <stdio.h>\nchar *y= (char *)0;\n\nint main() {\n  printf(\"0x%lx\\n\", (long)y);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input107.c",
    "content": "#include <stdio.h>\nchar *y[] = { \"fish\", \"cow\", NULL };\nchar *z= NULL;\n\nint main() {\n  int i;\n  char *ptr;\n  for (i=0; i < 3; i++) {\n    ptr= y[i];\n    if (ptr != (char *)0)\n      printf(\"%s\\n\", y[i]);\n    else\n      printf(\"NULL\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input108.c",
    "content": "int main() {\n  char *str= (void *)0;\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input109.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 17 - 1;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input110.c",
    "content": "#include <stdio.h>\n\nint x;\nint y;\n\nint main() {\n  x= 3; y= 15; y += x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y -= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y *= x; printf(\"%d\\n\", y);\n  x= 3; y= 15; y /= x; printf(\"%d\\n\", y);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input111.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 2000 + 3 + 4 * 5 + 6;\n  printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input112.c",
    "content": "#include <stdio.h>\nchar* y = NULL;\nint x= 10 + 6;\nint fred [ 2 + 3 ];\n\nint main() {\n  fred[2]= x;\n  printf(\"%d\\n\", fred[2]);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input113.c",
    "content": "#include <stdio.h>\nvoid fred(void);\n\nvoid fred(void) {\n  printf(\"fred says hello\\n\");\n}\n\nint main(void) {\n  fred(); return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input114.c",
    "content": "#include <stdio.h>\nint main() {\n  int x= 0x4a;\n  printf(\"%c\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input116.c",
    "content": "#include <stdio.h>\n\nstatic int counter=0;\nstatic int fred(void) { return(counter++); }\n\nint main(void) {\n  int i;\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input117.c",
    "content": "#include <stdio.h>\n\nstatic char *fred(void) {\n  return(\"Hello\");\n}\n\nint main(void) {\n  printf(\"%s\\n\", fred());\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input118.c",
    "content": "int main(void) {\n  static int x;\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input119.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  x= y != 3 ? 6 : 8; printf(\"%d\\n\", x);\n  x= (y == 3) ? 6 : 8; printf(\"%d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input120.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= y > 4 ? y + 2 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input121.c",
    "content": "#include <stdio.h>\n\nint x;\nint y= 3;\n\nint main() {\n  for (y= 0; y < 10; y++) {\n    x= (y < 4) ? y + 2 :\n       (y > 7) ? 1000 : y + 9;\n    printf(\"%d\\n\", x);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input122.c",
    "content": "#include <stdio.h>\n\nint x, y, z1, z2;\n\nint main() {\n  for (x= 0; x <= 1; x++) {\n    for (y= 0; y <= 1; y++) {\n      z1= x || y; z2= x && y;\n      printf(\"x %d, y %d, x || y %d, x && y %d\\n\", x, y, z1, z2);\n    }\n  }\n  \n  //z= x || y;\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input123.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int x;\n  for (x=0; x < 20; x++)\n    switch(x) {\n      case 2:\n      case 3:\n      case 5:\n      case 7:\n      case 11: printf(\"%2d infant prime\\n\", x); break;\n      case 13:\n      case 17:\n      case 19: printf(\"%2d teen   prime\\n\", x); break;\n      case 0:\n      case 1:\n      case 4:\n      case 6:\n      case 8:\n      case 9:\n      case 10:\n      case 12: printf(\"%2d infant composite\\n\", x); break;\n      default: printf(\"%2d teen   composite\\n\", x); break;\n    }\n\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input124.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary++;\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input125.c",
    "content": "#include <stdio.h>\n\nint ary[5];\nint *ptr;\nint x;\n\nint main() {\n  ary[3]= 2008;\n  ptr= ary;\t\t\t// Load ary's address into ptr\n  x= ary[3]; printf(\"%d\\n\", x);\n  x= ptr[3]; printf(\"%d\\n\", x); // Treat ptr as an array\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input126.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nint main() {\n  ary[3]= 2008;\n  ptr= &ary;\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input127.c",
    "content": "#include <stdio.h>\n\nint ary[5];\n\nvoid fred(int *ptr) {\t\t// Receive a pointer\n  printf(\"%d\\n\", ptr[3]);\n}\n\nint main() {\n  ary[3]= 2008;\n  printf(\"%d\\n\", ary[3]);\n  fred(ary);\t\t\t// Pass ary as a pointer\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input128.c",
    "content": "#include <stdio.h>\n\nstruct foo {\n  int val;\n  struct foo *next;\n};\n\nstruct foo head, mid, tail;\n\nint main() {\n  struct foo *ptr;\n  tail.val= 20; tail.next= NULL;\n  mid.val= 15; mid.next= &tail;\n  head.val= 10; head.next= &mid;\n\n  ptr= &head;\n  printf(\"%d %d\\n\", head.val, ptr->val);\n  printf(\"%d %d\\n\", mid.val, ptr->next->val);\n  printf(\"%d %d\\n\", tail.val, ptr->next->next->val);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input129.c",
    "content": "#include <stdio.h>\n\nint x= 6;\n\nint main() {\n  printf(\"%d\\n\", x++ ++);\n  return(0);\n}\n\n"
  },
  {
    "path": "64_6809_Target/tests/input130.c",
    "content": "#include <stdio.h>\n\nchar *x= \"foo\";\n\nint main() {\n  printf(\"Hello \" \"world\" \"\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input131.c",
    "content": "#include <stdio.h>\n\nvoid donothing() { }\n\nint main() {\n  int x=0;\n  printf(\"Doing nothing... \"); donothing();\n  printf(\"nothing done\\n\");\n\n  while (++x < 100) ;\n  printf(\"x is now %d\\n\", x);\n\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input132.c",
    "content": "extern int fred;\nint fred;\n\nint mary;\nextern int mary;\n\nint main() { return(0); }\n"
  },
  {
    "path": "64_6809_Target/tests/input133.c",
    "content": "#include <stdio.h>\n\nextern int fred[];\nint fred[23];\n\nchar mary[100];\nextern char mary[];\n\nvoid main() { printf(\"OK\\n\"); }\n"
  },
  {
    "path": "64_6809_Target/tests/input134.c",
    "content": "#include <stdio.h>\n\nchar y = 'a';\nchar *x;\n\nint main() {\n  x= &y;        if (x && y == 'a') printf(\"1st match\\n\");\n  x= NULL;      if (x && y == 'a') printf(\"2nd match\\n\");\n  x= &y; y='b'; if (x && y == 'a') printf(\"3rd match\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input135.c",
    "content": "#include <stdio.h>\n\nvoid fred() {\n  int x= 5;\n  printf(\"testing x\\n\");\n  if (x > 4) return;\n  printf(\"x below 5\\n\");\n}\n\nint main() {\n  fred();\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input136.c",
    "content": "#include <stdio.h>\n\nint add(int x, int y) {\n  return(x+y);\n}\n\nint main() {\n  int result;\n  result= 3 * add(2,3) - 5 * add(4,6);\n  printf(\"%d\\n\", result);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input137.c",
    "content": "#include <stdio.h>\n\nint a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8;\n\nint main() {\n  int x;\n  x= ((((((a + b) + c) + d) + e) + f) + g) + h;\n  x= a + (b + (c + (d + (e + (f + (g + h))))));\n  printf(\"x is %d\\n\", x);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input138.c",
    "content": "#include <stdio.h>\n\nint x, y, z;\n\nint a=1;\nint *aptr;\n\nint main() {\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x && y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // See if generic AND works\n  for (x=0; x <= 1; x++)\n    for (y=0; y <= 1; y++) {\n      z= x || y;\n      printf(\"%d %d | %d\\n\", x, y, z);\n    }\n\n  // Now some lazy evaluation\n  aptr= NULL;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  aptr= &a;\n  if (aptr && *aptr == 1)\n    printf(\"aptr points at 1\\n\");\n  else\n    printf(\"aptr is NULL or doesn't point at 1\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input139.c",
    "content": "#include <stdio.h>\n\nint same(int x) { return(x); }\n\nint main() {\n  int a= 3;\n\n  if (same(a) && same(a) >= same(a))\n    printf(\"same apparently\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input140.c",
    "content": "#include <stdio.h>\n\nint main() {\n  int  i;\n  int  ary[5];\n  char z;\n\n  // Write below the array\n  z= 'H';\n\n  // Fill the array\n  for (i=0; i < 5; i++)\n    ary[i]= i * i;\n\n  // Write above the array\n  i=14;\n\n  // Print out the array\n  for (i=0; i < 5; i++)\n    printf(\"%d\\n\", ary[i]);\n\n  // See if either side is OK\n  printf(\"%d %c\\n\", i, z);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input141.c",
    "content": "static int fred[5];\nint jim;\n\nint foo(int mary[6]) { return(5); }\n"
  },
  {
    "path": "64_6809_Target/tests/input142.c",
    "content": "static int fred[];\nint jim;\n"
  },
  {
    "path": "64_6809_Target/tests/input143.c",
    "content": "#include <stdio.h>\n\nchar foo;\nchar *a, *b, *c;\n\nint main() {\n\n  a= b= c= NULL;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  a= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  b= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  c= &foo;\n  if (a==NULL || b==NULL || c==NULL)\n    printf(\"One of the three is NULL\\n\");\n  else\n    printf(\"All  three  are non-NULL\\n\");\n\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input145.c",
    "content": "#include <stdio.h>\n\nchar *str= \"qwertyuiop\";\n\nint list[]= {3, 5, 7, 9, 11, 13, 15};\n\nint *lptr;\n\nint main() {\n  printf(\"%c\\n\", *str);\n  str= str + 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str -= 1; printf(\"%c\\n\", *str);\n\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input146.c",
    "content": "#include <stdio.h>\n\nchar *str= \"qwertyuiop\";\n\nint list[]= {3, 5, 7, 9, 11, 13, 15};\n\nint *lptr;\n\nint main() {\n  printf(\"%c\\n\", *str);\n  str= str + 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str += 1; printf(\"%c\\n\", *str);\n  str -= 1; printf(\"%c\\n\", *str);\n  str++; printf(\"%c\\n\", *str);\n  str--; printf(\"%c\\n\", *str);\n  ++str; printf(\"%c\\n\", *str);\n  --str; printf(\"%c\\n\\n\", *str);\n\n  lptr= list;\n  printf(\"%d\\n\", *lptr);\n  lptr= lptr + 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr += 1; printf(\"%d\\n\", *lptr);\n  lptr -= 1; printf(\"%d\\n\", *lptr);\n  lptr++   ; printf(\"%d\\n\", *lptr);\n  lptr--   ; printf(\"%d\\n\", *lptr);\n  ++lptr   ; printf(\"%d\\n\", *lptr);\n  --lptr   ; printf(\"%d\\n\", *lptr);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input147.c",
    "content": "#include <stdio.h>\n\nint a;\n\nint main() {\n  printf(\"%d\\n\", 24 % 9);\n  printf(\"%d\\n\", 31 % 11);\n  a= 24; a %= 9; printf(\"%d\\n\",a);\n  a= 31; a %= 11; printf(\"%d\\n\",a);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input148.c",
    "content": "#include <stdio.h>\n\nchar *argv[]= { \"unused\", \"-fish\", \"-cat\", \"owl\" };\nint argc= 4;\n\nint main() {\n  int i;\n\n  for (i = 1; i < argc; i++) {\n    printf(\"i is %d\\n\", i);\n    if (*argv[i] != '-') break;\n  }\n\n  while (i < argc) {\n    printf(\"leftover %s\\n\", argv[i]);\n    i++;\n  }\n\n  return (0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input149.c",
    "content": "#include <stdio.h>\n\nstatic int localOffset=0;\n\nstatic int newlocaloffset(int size) {\n  localOffset += (size > 4) ? size : 4;\n  return (-localOffset);\n}\n\nint main() {\n  int i, r;\n  for (i=1; i <= 12; i++) {\n    r= newlocaloffset(i);\n    printf(\"%d %d\\n\", i, r);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input150.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n\nstruct Svalue {\n  char *thing;\n  int vreg;\n  int intval;\n};\n\nstruct IR {\n  int label;\n  int op;\n  struct Svalue dst;\n  struct Svalue src1;\n  struct Svalue src2;\n  int jmplabel;\n};\n\nstruct foo {\n  int a;\n  int b;\n  struct Svalue *c;\n  int d;\n};\n\nstruct IR *fred;\nstruct foo jane;\n\nint main() {\n  fred= (struct IR *)malloc(sizeof(struct IR));\n  fred->label= 1;\n  fred->op= 2;\n  fred->dst.thing= NULL;\n  fred->dst.vreg=3;\n  fred->dst.intval=4;\n  fred->src1.thing= NULL;\n  fred->src1.vreg=5;\n  fred->src1.intval=6;\n  fred->src2.thing= NULL;\n  fred->src2.vreg=7;\n  fred->src2.intval=8;\n  fred->jmplabel= 9;\n\n  printf(\"%d %d %d\\n\",   fred->label, fred->op, fred->dst.vreg);\n  printf(\"%d %d %d\\n\",   fred->dst.intval, fred->src1.vreg, fred->src1.intval);\n  printf(\"%d %d %d\\n\\n\", fred->src2.vreg, fred->src2.intval, fred->jmplabel);\n\n  jane.c= (struct Svalue *)malloc(sizeof(struct Svalue));\n  jane.a= 1; jane.b= 2; jane.d= 4; \n  jane.c->thing= \"fish\";\n  jane.c->vreg= 3;\n  jane.c->intval= 5;\n\n  printf(\"%d %d %d\\n\", jane.a, jane.b, jane.c->vreg);\n  printf(\"%d %d %s\\n\", jane.d, jane.c->intval, jane.c->thing);\n\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input151.c",
    "content": "#include <stdio.h>\n\nstruct Location {\n  int type;             // One of the L_ values\n  char *name;           // A symbol's name\n  long intval;          // Offset, const value, label-id etc.\n  int primtype;         // 6809 primiive type, see P_POINTER below\n};\n\n#define NUMFREEREGS 16\n#define L_FREE 1\nstruct Location Locn[NUMFREEREGS];\n\nint main() {\n  int l=5;\n  Locn[l].type = 23;\n  printf(\"%d\\n\", Locn[l].type);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input152.c",
    "content": "#include <stdio.h>\nint main() {\n  int x=0;\n\n  while (x<10) {\n    switch(x) {\n      case 2: x++; break;\n      case 4: x=7; continue;\n    }\n    printf(\"%d\\n\", x);\n    x++;\n  }\n  \n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input153.c",
    "content": "#include <stdio.h>\n\nenum {\n  C_GLOBAL = 1,                 // Globally visible symbol\n  C_LOCAL,                      // Locally visible symbol\n  C_PARAM,                      // Locally visible function parameter\n  C_EXTERN,                     // External globally visible symbol\n  C_STATIC,                     // Static symbol, visible in one file\n  C_STRUCT,                     // A struct\n  C_UNION,                      // A union\n  C_MEMBER,                     // Member of a struct or union\n  C_ENUMTYPE,                   // A named enumeration type\n  C_ENUMVAL,                    // A named enumeration value\n  C_TYPEDEF,                    // A named typedef\n  C_STRLIT                      // Not a class: used to denote string literals\n};\n\nvoid fred(int class) {\n  char qbeprefix;\n  int *silly;\n  silly = &class;\n\n  // Get the relevant QBE prefix for the symbol\n  qbeprefix = ((class == C_GLOBAL) || (class == C_STATIC) ||\n               (class == C_EXTERN)) ? (char)'$' : (char)'%';\n  printf(\"class %d prefix %c\\n\", class, qbeprefix);\n\n}\n\nint main() {\n  int i;\n\n  for (i= C_GLOBAL; i<= C_STRLIT; i++)\n    fred(i);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input154.c",
    "content": "#include <stdio.h>\n\nint i;\nint j;\n\nint main() {\n\n  for (i=1; i<=10; i++) {\n    j= ((i==4) || (i==5)) ? 17 : 23;\n    printf(\"%d\\n\", j);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input155.c",
    "content": "#include <stdio.h>\n\nint i;\nint j;\n\nint main() {\n\n  for (i=1; i<=10; i++) {\n    j= ((i==4)) ? 17 : 23;\n    printf(\"%d\\n\", j);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input156.c",
    "content": "#include <stdio.h>\n\nint i;\nint j;\n\nint main() {\n\n    j= (5) ? 7 : 8; printf(\"%d\\n\", j);\n    j= (0) ? 7 : 8; printf(\"%d\\n\", j);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input157.c",
    "content": "#include <stdio.h>\n\nint main() {\n  if (5) printf(\"true\\n\");\n  if (0) printf(\"true\\n\");\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input159.c",
    "content": "#include <stdio.h>\n\nenum {\n  P_NONE, P_VOID = 16, P_CHAR = 32, P_INT = 48, P_LONG = 64,\n  P_STRUCT=80, P_UNION=96\n};\n\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\nint main() {\n\n  printf(\"%d\\n\", inttype(P_NONE));\n  printf(\"%d\\n\", inttype(P_VOID));\n  printf(\"%d\\n\", inttype(P_CHAR));\n  printf(\"%d\\n\", inttype(P_INT));\n  printf(\"%d\\n\", inttype(P_LONG));\n  printf(\"%d\\n\", inttype(P_STRUCT));\n  printf(\"%d\\n\", inttype(P_UNION));\n  printf(\"%d\\n\", inttype(P_CHAR+1));\n  printf(\"%d\\n\", inttype(P_INT+1));\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input160.c",
    "content": "#include <stdio.h>\n\nint x= '#';\n\nint main() {\n  switch(x) {\n    case 'x': printf(\"An x\\n\"); break;\n    case '#': printf(\"An #\\n\"); break;\n    default:  printf(\"No idea\\n\");\n  }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input161.c",
    "content": "#include <stdio.h>\n\nchar fred[5];\nchar *s;\n\nint main() {\n  s= fred;\n\n  *s = 'F'; s++;\n  *s++ = 'r';\n  *s++ = 'e';\n  *s++ = 'd';\n  *s++ = 0;\n  printf(\"%s\\n\", fred);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input162.c",
    "content": "#include <stdio.h>\n#include <string.h>\n\nvoid keyword(char *s) {\n\nprintf(\"search on %s: \", s); \n  switch (*s) {\n    case 'b': printf(\"Starts with b\\n\"); break;\n    case 'c': if (!strcmp(s, \"case\")) {\n\t\tprintf(\"It's case\\n\"); return;\n\t      }\n\t      printf(\"Starts with c\\n\"); break;\n    case 'v': if (!strcmp(s, \"void\")) {\n                printf(\"It's void\\n\"); return;\n              }\n\t      printf(\"Starts with v\\n\"); break;\n    default: printf(\"Not found\\n\");\n  }\n}\n\nint main() {\n  keyword(\"char\");\n  keyword(\"case\");\n  keyword(\"break\");\n  keyword(\"horse\");\n  keyword(\"void\");\n  keyword(\"piano\");\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input163.c",
    "content": "#include <stdio.h>\n#include <string.h>\n\nint keyword(char *s) {\n\n  switch (*s) {\n    case 'b': return(1);\n    case 'c': if (!strcmp(s, \"case\")) return(2);\n\t      return(3);\n    case 'v': if (!strcmp(s, \"void\")) return(4);\n\t      return(5);\n    default: return(6);\n  }\n  return(0);\n}\n\nint main() {\n  int i;\n\n  i= keyword(\"break\");    printf(\"break    %d\\n\", i);\n  i= keyword(\"case\");     printf(\"case     %d\\n\", i);\n  i= keyword(\"char\");     printf(\"char     %d\\n\", i);\n  i= keyword(\"void\");     printf(\"void     %d\\n\", i);\n  i= keyword(\"volatile\"); printf(\"volatile %d\\n\", i);\n  i= keyword(\"horse\");    printf(\"horse    %d\\n\", i);\n  i= keyword(\"piano\");    printf(\"piano    %d\\n\", i);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input164.c",
    "content": "#include <stdio.h>\n#include <string.h>\n\nchar *str= \"Hello there, this is a sentence. How about that?\";\n\nint main() {\n  char *comma, *dot;\n  int diff;\n  comma= strchr(str, ',');\n  dot= strchr(str, '.');\n  diff= dot - comma;\n  printf(\"dot comma difference is %d\\n\", diff);\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input165.c",
    "content": "#include <stdio.h>\n#include <string.h>\n\nchar *a= \"Hello\";\nchar *b= \"Goodbye\";\nchar *c= \"Fisherman\";\n\nint main() {\n  if (strcmp(a, b)) { printf(\"%s and %s are different\\n\", a, b); }\n  if (strcmp(b, c)) { printf(\"%s and %s are different\\n\", b, c); }\n  if (strcmp(a, c)) { printf(\"%s and %s are different\\n\", a, c); }\n  if (strcmp(a, a)) { printf(\"%s and %s are different\\n\", a, a); }\n  if (strcmp(b, b)) { printf(\"%s and %s are different\\n\", b, b); }\n  if (strcmp(c, c)) { printf(\"%s and %s are different\\n\", c, c); }\n  if (!strcmp(c, c)) { printf(\"%s and %s are the same\\n\", c, c); }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/input166.c",
    "content": "#include <stdio.h>\n\nchar str[5];\nchar *ptr;\n\nint scanch(int *slash) {\n  int c;\n  *slash=0;\n\n  c= *ptr; ptr++;\n  if (c == '\\\\') {\n    *slash=1;\n    c= *ptr; ptr++;\n    switch (c) {\n      case 'n':\n        return ('\\n');\n    }\n  }\n  return(c);\n}\n\nint main() {\n  int c;\n  int slash;\n  ptr= str;\n  str[0]= 'H';\n  str[1]= 'i';\n  str[2]= '\\\\';\n  str[3]= 'n';\n  str[4]= 0;\n\n  while (1) {\n    c= scanch(&slash);\n    if (c==0) break;\n    printf(\"c %d slash %d\\n\", c, slash);\n  }\n  return(0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/mktests",
    "content": "#!/bin/sh\n# Make the output files for each test\n\n# Build our compiler if needed\nif [ ! -f ../cwj ]\nthen (cd ..; make install)\nfi\n\nfor i in input*c\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then\n     ../cwj -o out $i 2> \"err.$i\"\n     # If the err file is empty\n     if [ ! -s \"err.$i\" ]\n     then\n        rm -f \"err.$i\"\n        cc -o out $i\n        ./out > \"out.$i\"\n      fi\n   fi\n   rm -f out out.s\ndone\n"
  },
  {
    "path": "64_6809_Target/tests/onetest",
    "content": "#!/bin/sh\n# Run one test and show the output\n# Build our compiler if needed\nif [ ! -f ../cparse6809 ]\nthen (cd ..; make install)\nfi\n\nif [ \"$#\" -ne 2 ]\nthen echo Usage: $0 cpu sourcefile; exit 1\nfi\n\nrm -f *_*\n\nbin=`echo $2 | sed 's/\\.c$//'`\n\n../wcc -v -X -o $bin -m $1 $2\n\nif [ \"$1\" = \"6809\" ]\nthen\n  emu6809 -d debug $bin\nfi\n\nif [ \"$1\" = \"qbe\" ]\nthen\n  ./$bin\nfi\n  \nexit 0\n"
  },
  {
    "path": "64_6809_Target/tests/out.input001.c",
    "content": "36\n10\n25\n"
  },
  {
    "path": "64_6809_Target/tests/out.input002.c",
    "content": "17\n"
  },
  {
    "path": "64_6809_Target/tests/out.input003.c",
    "content": "1\n2\n3\n4\n5\n"
  },
  {
    "path": "64_6809_Target/tests/out.input004.c",
    "content": "1\n1\n1\n1\n1\n1\n1\n1\n1\n"
  },
  {
    "path": "64_6809_Target/tests/out.input005.c",
    "content": "6\n"
  },
  {
    "path": "64_6809_Target/tests/out.input006.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "64_6809_Target/tests/out.input007.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "64_6809_Target/tests/out.input008.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "64_6809_Target/tests/out.input009.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"
  },
  {
    "path": "64_6809_Target/tests/out.input010.c",
    "content": "20\n10\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n"
  },
  {
    "path": "64_6809_Target/tests/out.input011.c",
    "content": "10\n20\n30\n1\n2\n3\n4\n5\n253\n254\n255\n0\n1\n2\n3\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "64_6809_Target/tests/out.input012.c",
    "content": "5\n"
  },
  {
    "path": "64_6809_Target/tests/out.input013.c",
    "content": "23\n56\n"
  },
  {
    "path": "64_6809_Target/tests/out.input014.c",
    "content": "10\n20\n30\n"
  },
  {
    "path": "64_6809_Target/tests/out.input015.c",
    "content": "18\n18\n12\n12\n"
  },
  {
    "path": "64_6809_Target/tests/out.input016.c",
    "content": "12\n18\n"
  },
  {
    "path": "64_6809_Target/tests/out.input017.c",
    "content": "19\n12\n"
  },
  {
    "path": "64_6809_Target/tests/out.input018.c",
    "content": "34\n34\n"
  },
  {
    "path": "64_6809_Target/tests/out.input018a.c",
    "content": "15\n16\n"
  },
  {
    "path": "64_6809_Target/tests/out.input019.c",
    "content": "30\n"
  },
  {
    "path": "64_6809_Target/tests/out.input020.c",
    "content": "12\n"
  },
  {
    "path": "64_6809_Target/tests/out.input021.c",
    "content": "10\nHello world\n"
  },
  {
    "path": "64_6809_Target/tests/out.input022.c",
    "content": "12\n12\n12\n13\n13\n13\n13\n13\n13\n35\n35\n35\n"
  },
  {
    "path": "64_6809_Target/tests/out.input023.c",
    "content": "-23\n100\n-2\n0\n1\n0\n13\n14\nHello world\n"
  },
  {
    "path": "64_6809_Target/tests/out.input024.c",
    "content": "2\n59\n57\n8\n7\n"
  },
  {
    "path": "64_6809_Target/tests/out.input025.c",
    "content": "10\n20\n30\n5\n15\n25\n"
  },
  {
    "path": "64_6809_Target/tests/out.input026.c",
    "content": "13\n23\n34\n44\n54\n64\n74\n84\n94\n95\n96\n"
  },
  {
    "path": "64_6809_Target/tests/out.input027.c",
    "content": "1\n2\n3\n4\n5\n6\n7\n8\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "64_6809_Target/tests/out.input028.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "64_6809_Target/tests/out.input029.c",
    "content": "1\n2\n3\n5\n8\n13\n21\n34\n9\n"
  },
  {
    "path": "64_6809_Target/tests/out.input030.c",
    "content": "int printf(char *fmt, ...);\n\nint open(char *pathname, int flags);\nint read(int fd, char *buf, int count);\nint write(int fd, void *buf, int count);\nint close(int fd);\n\nchar *buf;\n\nint main() {\n  int zin;\n  int cnt;\n\n  buf= \"                                                             \";\n  zin = open(\"input030.c\", 0);\n  if (zin == -1) {\n    return (1);\n  }\n  while ((cnt = read(zin, buf, 60)) > 0) {\n    write(1, buf, cnt);\n  }\n  close(zin);\n  return (0);\n}\n"
  },
  {
    "path": "64_6809_Target/tests/out.input053.c",
    "content": "Hello world, 23\n"
  },
  {
    "path": "64_6809_Target/tests/out.input054.c",
    "content": "Hello world, 0\nHello world, 1\nHello world, 2\nHello world, 3\nHello world, 4\nHello world, 5\nHello world, 6\nHello world, 7\nHello world, 8\nHello world, 9\nHello world, 10\nHello world, 11\nHello world, 12\nHello world, 13\nHello world, 14\nHello world, 15\nHello world, 16\nHello world, 17\nHello world, 18\nHello world, 19\n"
  },
  {
    "path": "64_6809_Target/tests/out.input055.c",
    "content": "Hello world\nArgument 0 is ./out\n"
  },
  {
    "path": "64_6809_Target/tests/out.input058.c",
    "content": "12\n99\n4005\n4116\n4116\n"
  },
  {
    "path": "64_6809_Target/tests/out.input063.c",
    "content": "25\n"
  },
  {
    "path": "64_6809_Target/tests/out.input067.c",
    "content": "5\n17\n"
  },
  {
    "path": "64_6809_Target/tests/out.input070.c",
    "content": "56\n"
  },
  {
    "path": "64_6809_Target/tests/out.input071.c",
    "content": "0\n1\n2\n3\n4\n7\n8\n9\n10\n11\n12\n13\n14\nDone\n"
  },
  {
    "path": "64_6809_Target/tests/out.input074.c",
    "content": "100\n5\n7\n100\n100\n"
  },
  {
    "path": "64_6809_Target/tests/out.input080.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n5 11\n"
  },
  {
    "path": "64_6809_Target/tests/out.input081.c",
    "content": "0 1\n1 3\n2 5\n3 7\n4 9\n"
  },
  {
    "path": "64_6809_Target/tests/out.input082.c",
    "content": "15 >= x > 5\n"
  },
  {
    "path": "64_6809_Target/tests/out.input083.c",
    "content": " 5 <  6 <= 10\n 5 <  7 <= 10\n 5 <  8 <= 10\n 5 <  9 <= 10\n 5 < 10 <= 10\n10 < 11\n"
  },
  {
    "path": "64_6809_Target/tests/out.input084.c",
    "content": "2 3\nf f\n"
  },
  {
    "path": "64_6809_Target/tests/out.input088.c",
    "content": "5 6\n"
  },
  {
    "path": "64_6809_Target/tests/out.input089.c",
    "content": "23 H Hello world\n"
  },
  {
    "path": "64_6809_Target/tests/out.input090.c",
    "content": "23 100 H Hello world\n"
  },
  {
    "path": "64_6809_Target/tests/out.input091.c",
    "content": "1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n0\n0\n0\n0\n0\n"
  },
  {
    "path": "64_6809_Target/tests/out.input099.c",
    "content": "EOF\n=\n||\n&&\n|\n^\n&\n==\n!=\n,\n>\n<=\n>=\n<<\n>>\n+\n-\n*\n/\n++\n--\n~\n!\nvoid\nchar\nint\nlong\nif\nelse\nwhile\nfor\nreturn\nstruct\nunion\nenum\ntypedef\nextern\nbreak\ncontinue\nswitch\ncase\ndefault\nintlit\nstrlit\n;\nidentifier\n{\n}\n(\n)\n[\n]\n,\n.\n->\n:\n"
  },
  {
    "path": "64_6809_Target/tests/out.input100.c",
    "content": "Hello world 17 20\n"
  },
  {
    "path": "64_6809_Target/tests/out.input101.c",
    "content": "0xff\n0x0\n"
  },
  {
    "path": "64_6809_Target/tests/out.input106.c",
    "content": "0x0\n"
  },
  {
    "path": "64_6809_Target/tests/out.input107.c",
    "content": "fish\ncow\nNULL\n"
  },
  {
    "path": "64_6809_Target/tests/out.input108.c",
    "content": ""
  },
  {
    "path": "64_6809_Target/tests/out.input109.c",
    "content": "16\n"
  },
  {
    "path": "64_6809_Target/tests/out.input110.c",
    "content": "18\n12\n45\n5\n"
  },
  {
    "path": "64_6809_Target/tests/out.input111.c",
    "content": "2029\n"
  },
  {
    "path": "64_6809_Target/tests/out.input112.c",
    "content": "16\n"
  },
  {
    "path": "64_6809_Target/tests/out.input113.c",
    "content": "fred says hello\n"
  },
  {
    "path": "64_6809_Target/tests/out.input114.c",
    "content": "J\n"
  },
  {
    "path": "64_6809_Target/tests/out.input116.c",
    "content": "0\n1\n2\n3\n4\n"
  },
  {
    "path": "64_6809_Target/tests/out.input117.c",
    "content": "Hello\n"
  },
  {
    "path": "64_6809_Target/tests/out.input119.c",
    "content": "8\n6\n"
  },
  {
    "path": "64_6809_Target/tests/out.input120.c",
    "content": "9\n10\n11\n12\n13\n7\n8\n9\n10\n11\n"
  },
  {
    "path": "64_6809_Target/tests/out.input121.c",
    "content": "2\n3\n4\n5\n13\n14\n15\n16\n1000\n1000\n"
  },
  {
    "path": "64_6809_Target/tests/out.input122.c",
    "content": "x 0, y 0, x || y 0, x && y 0\nx 0, y 1, x || y 1, x && y 0\nx 1, y 0, x || y 1, x && y 0\nx 1, y 1, x || y 1, x && y 1\n"
  },
  {
    "path": "64_6809_Target/tests/out.input123.c",
    "content": " 0 infant composite\n 1 infant composite\n 2 infant prime\n 3 infant prime\n 4 infant composite\n 5 infant prime\n 6 infant composite\n 7 infant prime\n 8 infant composite\n 9 infant composite\n10 infant composite\n11 infant prime\n12 infant composite\n13 teen   prime\n14 teen   composite\n15 teen   composite\n16 teen   composite\n17 teen   prime\n18 teen   composite\n19 teen   prime\n"
  },
  {
    "path": "64_6809_Target/tests/out.input125.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "64_6809_Target/tests/out.input127.c",
    "content": "2008\n2008\n"
  },
  {
    "path": "64_6809_Target/tests/out.input128.c",
    "content": "10 10\n15 15\n20 20\n"
  },
  {
    "path": "64_6809_Target/tests/out.input130.c",
    "content": "Hello world\n"
  },
  {
    "path": "64_6809_Target/tests/out.input131.c",
    "content": "Doing nothing... nothing done\nx is now 100\n"
  },
  {
    "path": "64_6809_Target/tests/out.input132.c",
    "content": ""
  },
  {
    "path": "64_6809_Target/tests/out.input133.c",
    "content": "OK\n"
  },
  {
    "path": "64_6809_Target/tests/out.input134.c",
    "content": "1st match\n"
  },
  {
    "path": "64_6809_Target/tests/out.input135.c",
    "content": "testing x\n"
  },
  {
    "path": "64_6809_Target/tests/out.input136.c",
    "content": "-35\n"
  },
  {
    "path": "64_6809_Target/tests/out.input137.c",
    "content": "x is 36\n"
  },
  {
    "path": "64_6809_Target/tests/out.input138.c",
    "content": "0 0 | 0\n0 1 | 0\n1 0 | 0\n1 1 | 1\n0 0 | 0\n0 1 | 1\n1 0 | 1\n1 1 | 1\naptr is NULL or doesn't point at 1\naptr points at 1\n"
  },
  {
    "path": "64_6809_Target/tests/out.input139.c",
    "content": "same apparently\n"
  },
  {
    "path": "64_6809_Target/tests/out.input140.c",
    "content": "0\n1\n4\n9\n16\n5 H\n"
  },
  {
    "path": "64_6809_Target/tests/out.input143.c",
    "content": "One of the three is NULL\nOne of the three is NULL\nOne of the three is NULL\nAll  three  are non-NULL\n"
  },
  {
    "path": "64_6809_Target/tests/out.input145.c",
    "content": "q\nw\ne\nr\ne\n3\n5\n7\n9\n7\n"
  },
  {
    "path": "64_6809_Target/tests/out.input146.c",
    "content": "q\nw\ne\nr\ne\nr\ne\nr\ne\n\n3\n5\n7\n9\n7\n9\n7\n9\n7\n"
  },
  {
    "path": "64_6809_Target/tests/out.input147.c",
    "content": "6\n9\n6\n9\n"
  },
  {
    "path": "64_6809_Target/tests/out.input148.c",
    "content": "i is 1\ni is 2\ni is 3\nleftover owl\n"
  },
  {
    "path": "64_6809_Target/tests/out.input149.c",
    "content": "1 -4\n2 -8\n3 -12\n4 -16\n5 -21\n6 -27\n7 -34\n8 -42\n9 -51\n10 -61\n11 -72\n12 -84\n"
  },
  {
    "path": "64_6809_Target/tests/out.input150.c",
    "content": "1 2 3\n4 5 6\n7 8 9\n\n1 2 3\n4 5 fish\n"
  },
  {
    "path": "64_6809_Target/tests/out.input151.c",
    "content": "23\n"
  },
  {
    "path": "64_6809_Target/tests/out.input152.c",
    "content": "0\n1\n3\n7\n8\n9\n"
  },
  {
    "path": "64_6809_Target/tests/out.input153.c",
    "content": "class 1 prefix $\nclass 2 prefix %\nclass 3 prefix %\nclass 4 prefix $\nclass 5 prefix $\nclass 6 prefix %\nclass 7 prefix %\nclass 8 prefix %\nclass 9 prefix %\nclass 10 prefix %\nclass 11 prefix %\nclass 12 prefix %\n"
  },
  {
    "path": "64_6809_Target/tests/out.input154.c",
    "content": "23\n23\n23\n17\n17\n23\n23\n23\n23\n23\n"
  },
  {
    "path": "64_6809_Target/tests/out.input155.c",
    "content": "23\n23\n23\n17\n23\n23\n23\n23\n23\n23\n"
  },
  {
    "path": "64_6809_Target/tests/out.input156.c",
    "content": "7\n8\n"
  },
  {
    "path": "64_6809_Target/tests/out.input157.c",
    "content": "true\n"
  },
  {
    "path": "64_6809_Target/tests/out.input159.c",
    "content": "0\n0\n1\n1\n1\n0\n0\n0\n0\n"
  },
  {
    "path": "64_6809_Target/tests/out.input160.c",
    "content": "An #\n"
  },
  {
    "path": "64_6809_Target/tests/out.input161.c",
    "content": "Fred\n"
  },
  {
    "path": "64_6809_Target/tests/out.input162.c",
    "content": "search on char: Starts with c\nsearch on case: It's case\nsearch on break: Starts with b\nsearch on horse: Not found\nsearch on void: It's void\nsearch on piano: Not found\n"
  },
  {
    "path": "64_6809_Target/tests/out.input163.c",
    "content": "break    1\ncase     2\nchar     3\nvoid     4\nvolatile 5\nhorse    6\npiano    6\n"
  },
  {
    "path": "64_6809_Target/tests/out.input164.c",
    "content": "dot comma difference is 20\n"
  },
  {
    "path": "64_6809_Target/tests/out.input165.c",
    "content": "Hello and Goodbye are different\nGoodbye and Fisherman are different\nHello and Fisherman are different\nFisherman and Fisherman are the same\n"
  },
  {
    "path": "64_6809_Target/tests/out.input166.c",
    "content": "c 72 slash 0\nc 105 slash 0\nc 10 slash 1\n"
  },
  {
    "path": "64_6809_Target/tests/runtests",
    "content": "#!/bin/sh\n# Run each test and compare\n# against known good output\n\n# We need a CPU name\nif [ \"$#\" -ne 1 ]\nthen echo \"Usage: $0 cpuname, e.g $0 6809\"; exit 1\nfi\n\n# Build our compiler if needed\nif [ ! -f ../wcc ]\nthen (cd ..; make install)\nfi\n\n# Try to use each input source file\nfor i in input*c\n# We can't do anything if there's no file to test against\ndo if [ ! -f \"out.$i\" -a ! -f \"err.$i\" ]\n   then echo \"Can't run test on $i, no output file!\"\n\n   # Output file: compile the source, run it and\n   # capture the output, and compare it against\n   # the known-good output\n   else if [ -f \"out.$i\" ]\n        then\n\t  # Print the test name, compile it\n\t  # with our compiler\n          echo -n $i\n\n\t  ../wcc -o out -m $1 $i\n\n          emu6809 ./out > trial.$i\n\t  rm -f out\n\n  \t  # Compare this agains the correct output\n          cmp -s \"out.$i\" \"trial.$i\"\n\n\t  # If different, announce failure\n          # and print out the difference\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"out.$i\" \"trial.$i\"\n            echo\n\t    exit 0\n\n\t  # No failure, so announce success\n          else echo \": OK\"\n          fi\n\n   # Error file: compile the source and\n   # capture the error messages. Compare\n   # against the known-bad output. Same\n   # mechanism as before\n   else if [ -f \"err.$i\" ]\n        then\n          echo -n $i\n\t  ../wcc -o out -m $1 $i 2> \"trial.$i\"\n\n          cmp -s \"err.$i\" \"trial.$i\"\n          if [ \"$?\" -eq \"1\" ]\n          then echo \": failed\"\n            diff -c \"err.$i\" \"trial.$i\"\n            echo\n          else echo \": OK\"\n          fi\n        fi\n     fi\n   fi\n   rm -f out out.s \"trial.$i\"\ndone\n"
  },
  {
    "path": "64_6809_Target/tree.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"misc.h\"\n#include \"parse.h\"\n#include \"sym.h\"\n#include \"gen.h\"\n\n// AST tree functions\n// Copyright (c) 2019,2024 Warren Toomey, GPL3\n\n#undef DEBUG\n\n// Used to enumerate the AST nodes\nstatic int nodeid= 1;\n\n// Build and return a generic AST node\nstruct ASTnode *mkastnode(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct ASTnode *left,\n\t\t\t  struct ASTnode *mid,\n\t\t\t  struct ASTnode *right,\n\t\t\t  struct symtable *sym, int intvalue) {\n  struct ASTnode *n;\n\n  // Malloc a new ASTnode\n  n = (struct ASTnode *) malloc(sizeof(struct ASTnode));\n  if (n == NULL)\n    fatal(\"Unable to malloc in mkastnode()\");\n\n  // Copy in the field values and return it\n  n->nodeid= nodeid++;\n  n->op = op;\n  n->type = type;\n  n->ctype = ctype;\n  n->left = left;\n  n->mid = mid;\n  n->right = right;\n  n->leftid= 0;\n  n->midid= 0;\n  n->rightid= 0;\n#ifdef DEBUG\nfprintf(stderr, \"mkastnodeA l %d m %d r %d\\n\", n->leftid, n->midid, n->rightid);\n#endif\n  if (left!=NULL) n->leftid= left->nodeid;\n  if (mid!=NULL) n->midid= mid->nodeid;\n  if (right!=NULL) n->rightid= right->nodeid;\n#ifdef DEBUG\nfprintf(stderr, \"mkastnodeB l %d m %d r %d\\n\", n->leftid, n->midid, n->rightid);\n#endif\n  n->sym = sym;\n  if (sym != NULL) {\n    n->name= sym->name;\n    n->symid= sym->id;\n  } else {\n    n->name= NULL;\n    n->symid= 0;\n  }\n  n->a_intvalue = intvalue;\n  n->linenum = 0;\n  n->rvalue = 0;\n  return (n);\n}\n\n\n// Make an AST leaf node\nstruct ASTnode *mkastleaf(int op, int type,\n\t\t\t  struct symtable *ctype,\n\t\t\t  struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, NULL, NULL, NULL, sym, intvalue));\n}\n\n// Make a unary AST node: only one child\nstruct ASTnode *mkastunary(int op, int type,\n\t\t\t   struct symtable *ctype,\n\t\t\t   struct ASTnode *left,\n\t\t\t   struct symtable *sym, int intvalue) {\n  return (mkastnode(op, type, ctype, left, NULL, NULL, sym, intvalue));\n}\n\n// Free the given AST node\nvoid freeASTnode(struct ASTnode *tree) {\n  if (tree==NULL) return;\n  if (tree->name != NULL) free(tree->name);\n  free(tree);\n}\n\n// Free the contents of a tree. Possibly\n// because of tree optimisation, sometimes\n// left and right are the same sub-nodes.\n// Free the names if asked to do so.\nvoid freetree(struct ASTnode *tree, int freenames) {\n  if (tree==NULL) return;\n\n  if (tree->left!=NULL) freetree(tree->left, freenames);\n  if (tree->mid!=NULL) freetree(tree->mid, freenames);\n  if (tree->right!=NULL && tree->right!=tree->left)\n\t\t\t\t\tfreetree(tree->right, freenames);\n  if (freenames && tree->name != NULL) free(tree->name);\n  free(tree);\n}\n\n#ifndef WRITESYMS\n\n// We record the id of the last function that we loaded.\n// and the highest index in the array below\nstatic int lastFuncid= -1;\nstatic int hiFuncid;\n\n// We also keep an array of AST node offsets that\n// represent the functions in the AST file\nlong *Funcoffset;\n\n// Given an AST node id, load that AST node from the AST file.\n// If nextfunc is set, find the next AST node which is a function.\n// Allocate and return the node or NULL if it can't be found.\nstruct ASTnode *loadASTnode(int id, int nextfunc) {\n  long offset, idxoff;\n  struct ASTnode *node;\n\n  // Do nothing if nothing to do\n  if (id==0 && nextfunc==0) return(NULL);\n\n#ifdef DEBUG\n  fprintf(stderr, \"loadASTnode id %d nextfunc %d\\n\", id, nextfunc);\n\n  if (id < 0)\n    fatal(\"negative id in loadASTnode()\");\n#endif\n\n  // Determine the offset of the node.\n  // Use the function offset array, or\n  // use the AST index file otherwise\n  if (nextfunc==1) {\n    lastFuncid++;\n    if (lastFuncid > hiFuncid)\n      return(NULL);\n    offset= Funcoffset[lastFuncid];\n  } else {\n    idxoff= id * sizeof(long);\n    fseek(Idxfile, idxoff, SEEK_SET);\n    fread(&offset, sizeof(long), 1, Idxfile);\n  }\n\n  // Allocate a node\n  node= (struct ASTnode *)malloc(sizeof(struct ASTnode));\n  if (node==NULL)\n    fatal(\"Cannot malloc an AST node in loadASTnode\");\n\n  // Read the node in from the AST file. Give up if EOF\n  fseek(Infile, offset, SEEK_SET);\n  if (fread(node, sizeof(struct ASTnode), 1, Infile)!=1) {\n    free(node); return(NULL);\n  }\n\n#ifdef DEBUG\n  // Check that the node we loaded was the one we wanted\n  if (id!=0 && id!=node->nodeid)\n    fprintf(stderr, \"Wanted AST node id %d, got %d\\n\", id, node->nodeid);\n#endif\n\n  // If there is a string/identifier literal, get it\n  if (node->name!=NULL) {\n    fgetstr(Text, TEXTLEN + 1, Infile);\n    node->name= strdup(Text);\n    if (node->name==NULL)\n      fatal(\"Unable to malloc string literal in deserialiseAST()\");\n\n#ifndef DETREE\n    // If this wasn't a string literal\n    // search for the actual symbol and link it in\n    if (node->op != A_STRLIT) {\n      node->sym= findSymbol(NULL, 0, node->symid);\n      if (node->sym==NULL)\n        fatald(\"Can't find symbol with id\", node->symid);\n    }\n#endif\n  }\n\n  // Set the pointers to NULL to trip us up!\n  node->left= node->mid= node->right= NULL;\n\n#ifndef DETREE\n  // If this is a function, set the global\n  // Functionid and create an endlabel for it.\n  // Update the lastFuncnode too.\n  if (node->op== A_FUNCTION) {\n    Functionid= node->sym;\n    Functionid->st_endlabel= genlabel();\n  }\n#endif\n\n  // Return the node that we found\n#ifdef DEBUG\n  fprintf(stderr, \"Found AST node id %d\\n\", node->nodeid);\n#endif\n  return(node);\n}\n\n// Using the open AST file and the newly-created\n// index file, build a list of AST file offsets\n// for each AST node in the AST file.\nvoid mkASTidxfile(void) {\n  struct ASTnode *node;\n  long offset, idxoff;\n\n  // Allocate a node and at least some Funcoffset area\n  node= (struct ASTnode *)malloc(sizeof(struct ASTnode));\n  Funcoffset= (long *)malloc(sizeof(long));\n  if (node==NULL || Funcoffset==NULL)\n    fatal(\"Cannot malloc an AST node in loadASTnode\");\n\n  while (1) {\n    // Get the current offset\n    offset = ftell(Infile);\n#ifdef DEBUG\n    if (sizeof(long)==4)\n      fprintf(stderr, \"A offset %ld sizeof ASTnode %d\\n\", offset,\n\t\t\tsizeof(struct ASTnode));\n    else\n      fprintf(stderr, \"A offset %ld sizeof ASTnode %ld\\n\", offset,\n\t\t\tsizeof(struct ASTnode));\n#endif\n\n    // Read in the next node, stop if none\n    if (fread(node, sizeof(struct ASTnode), 1, Infile)!=1) {\n      break;\n    }\n#ifdef DEBUG\n    fprintf(stderr, \"Node %d at offset %ld\\n\", node->nodeid, offset);\n    fprintf(stderr, \"Node %d left %d mid %d right %d\\n\", node->nodeid,\n        node->leftid, node->midid, node->rightid);\n#endif\n\n    // If there is a string/identifier literal, get it\n    if (node->name!=NULL) {\n      fgetstr(Text, TEXTLEN + 1, Infile);\n#ifdef DEBUG\n    fprintf(stderr, \"  name %s\\n\", Text);\n#endif\n    }\n    \n    // Save the node's offset at its index position in the file.\n    idxoff= node->nodeid * sizeof(long);\n\n    fseek(Idxfile, idxoff, SEEK_SET);\n    fwrite(&offset, sizeof(long), 1, Idxfile);\n\n    // If this node is a function, increase the size\n    // of the function index array and save the offset\n    if (node->op==A_FUNCTION) {\n      lastFuncid++;\n      Funcoffset= (long *)realloc(Funcoffset, sizeof(long)* (lastFuncid+1));\n      Funcoffset[lastFuncid]= offset;\n    }\n  }\n\n  // Reset before we start using the array\n  hiFuncid= lastFuncid; lastFuncid= -1;\n  free(node);\n}\n#endif // WRITESYMS\n"
  },
  {
    "path": "64_6809_Target/tree.h",
    "content": "/* tree.c */\nstruct ASTnode *mkastnode(int op, int type, struct symtable *ctype, struct ASTnode *left, struct ASTnode *mid, struct ASTnode *right, struct symtable *sym, int intvalue);\nstruct ASTnode *mkastleaf(int op, int type, struct symtable *ctype, struct symtable *sym, int intvalue);\nstruct ASTnode *mkastunary(int op, int type, struct symtable *ctype, struct ASTnode *left, struct symtable *sym, int intvalue);\nvoid freeASTnode(struct ASTnode *tree);\nvoid freetree(struct ASTnode *tree, int freenames);\nstruct ASTnode *loadASTnode(int id, int nextfunc);\nvoid mkASTidxfile(void);\n"
  },
  {
    "path": "64_6809_Target/tstring.c",
    "content": "// List of token strings, for debugging purposes\nchar *Tstring[] = {\n  \"EOF\", \"=\", \"+=\", \"-=\", \"*=\", \"/=\", \"%=\",\n  \"?\", \"||\", \"&&\", \"|\", \"^\", \"&\",\n  \"==\", \"!=\", \"<\", \">\", \"<=\", \">=\", \"<<\", \">>\",\n  \"+\", \"-\", \"*\", \"/\", \"%\", \"++\", \"--\", \"~\", \"!\",\n  \"void\", \"char\", \"int\", \"long\",\n  \"if\", \"else\", \"while\", \"for\", \"return\",\n  \"struct\", \"union\", \"enum\", \"typedef\",\n  \"extern\", \"break\", \"continue\", \"switch\",\n  \"case\", \"default\", \"sizeof\", \"static\",\n  \"intlit\", \"strlit\", \";\", \"identifier\",\n  \"{\", \"}\", \"(\", \")\", \"[\", \"]\", \",\", \".\",\n  \"->\", \":\", \"...\", \"charlit\", \"filename\", \"linenum\"\n};\n"
  },
  {
    "path": "64_6809_Target/types.c",
    "content": "#include \"defs.h\"\n#include \"data.h\"\n#include \"gen.h\"\n#include \"misc.h\"\n#include \"target.h\"\n#include \"tree.h\"\n\n// Types and type handling\n// Copyright (c) 2019 Warren Toomey, GPL3\n\n// Return true if a type is an int type\n// of any size, false otherwise\nint inttype(int type) {\n  return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));\n}\n\n// Return true if a type is of pointer type\nint ptrtype(int type) {\n  return ((type & 0xf) != 0);\n}\n\n// Given a primitive type, return\n// the type which is a pointer to it\nint pointer_to(int type) {\n  if ((type & 0xf) == 0xf)\n    fatald(\"Unrecognised in pointer_to: type\", type);\n  return (type + 1);\n}\n\n// Given a pointer type, return\n// the type which it points to\nint value_at(int type) {\n  if ((type & 0xf) == 0x0)\n    fatald(\"Unrecognised in value_at: type\", type);\n  return (type - 1);\n}\n\n// Given a type and a composite type pointer, return\n// the size of this type in bytes\nint typesize(int type, struct symtable *ctype) {\n  if (type == P_STRUCT || type == P_UNION)\n    return (ctype->size);\n  return (genprimsize(type));\n}\n\n// Given an AST tree and a type which we want it to become,\n// possibly modify the tree by widening or scaling so that\n// it is compatible with this type. Return the original tree\n// if no changes occurred, a modified tree, or NULL if the\n// tree is not compatible with the given type.\n// If this will be part of a binary operation, the AST op is not zero.\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype,\n\t\t\t    struct symtable *rctype, int op) {\n  int ltype;\n  int lsize, rsize;\n\n  ltype = tree->type;\n\n  // For A_LOGOR and A_LOGAND, both types have to be int or pointer types\n  if (op==A_LOGOR || op==A_LOGAND) {\n    if (!inttype(ltype) && !ptrtype(ltype))\n      return(NULL);\n    if (!inttype(ltype) && !ptrtype(rtype))\n      return(NULL);\n    return (tree);\n  }\n\n  // No idea on these yet\n  if (ltype == P_STRUCT || ltype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n  if (rtype == P_STRUCT || rtype == P_UNION)\n    fatal(\"Don't know how to do this yet\");\n\n  // Compare scalar int types\n  if (inttype(ltype) && inttype(rtype)) {\n\n    // Both types same, nothing to do\n    if (ltype == rtype)\n      return (tree);\n\n    // Get the sizes for each type\n    lsize = typesize(ltype, NULL);\n    rsize = typesize(rtype, NULL);\n\n    // The tree's type size is too big and we can't narrow\n    if (lsize > rsize)\n      return (NULL);\n\n    // Widen to the right\n    if (rsize > lsize)\n      return (mkastunary(A_WIDEN, rtype, NULL, tree, NULL, 0));\n  }\n\n  // For pointers\n  if (ptrtype(ltype) && ptrtype(rtype)) {\n    // We can compare them\n    if (op >= A_EQ && op <= A_GE)\n      return (tree);\n\n    // NOTE We can do subtraction, but we should unscale\n    // by the size of the things that the pointers point at.\n    // For now, we only do char pointers.\n    if (op== A_SUBTRACT && ltype== pointer_to(P_CHAR) && ltype==rtype) {\n      tree->type= P_INT;\n      return (tree);\n    }\n\n    // A comparison of the same type for a non-binary operation is OK,\n    // or when either tree is of  `void *` type.\n    if (op == 0 &&\n      (ltype == rtype || ltype == pointer_to(P_VOID) || rtype == pointer_to(P_VOID)) )\n      return (tree);\n  }\n\n  // We can scale only on add and subtract operations\n  if (op == A_ADD || op == A_SUBTRACT ||\n      op == A_ASPLUS || op == A_ASMINUS) {\n\n    // Left is int type, right is pointer type and the size\n    // of the original type is >1: scale the left\n    if (inttype(ltype) && ptrtype(rtype)) {\n      rsize = typesize(value_at(rtype), rctype);\n      if (rsize > 1)\n\treturn (mkastunary(A_SCALE, rtype, rctype, tree, NULL, rsize));\n      else\n        // No need to scale, but we need to widen to pointer size\n        return (mkastunary(A_WIDEN, rtype, NULL, tree, NULL, 0));\n    }\n  }\n\n  // If we get here, the types are not compatible\n  return (NULL);\n}\n"
  },
  {
    "path": "64_6809_Target/types.h",
    "content": "/* types.c */\nint inttype(int type);\nint ptrtype(int type);\nint pointer_to(int type);\nint value_at(int type);\nint typesize(int type, struct symtable *ctype);\nstruct ASTnode *modify_type(struct ASTnode *tree, int rtype, struct symtable *rctype, int op);\n"
  },
  {
    "path": "64_6809_Target/wcc.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <unistd.h>\n#include <string.h>\n#include <sys/wait.h>\n#include \"dirs.h\"\n#include \"wcc.h\"\n\n// Compiler setup and top-level execution\n// Copyright (c) 2024 Warren Toomey, GPL3\n\n// List of phases\n#define CPP_PHASE\t0\n#define TOK_PHASE\t1\n#define PARSE_PHASE\t2\n#define GEN_PHASE\t3\n#define QBEPEEP_PHASE\t4\t// Either run QBE or the peephole optimiser\n#define ASM_PHASE\t5\n#define LINK_PHASE\t6\n\n// A struct to keep a linked list of filenames\nstruct filelist {\n  char *name;\n  struct filelist *next;\n};\n\n#define CPU_QBE\t\t1\n#define CPU_6809\t2\n\n// Global variables\nint cpu = CPU_QBE;\t\t// What CPU/platform we are targetting\nint last_phase = LINK_PHASE;\t// Which is the last phase\nint verbose = 0;\t\t// Print out the phase details?\nint keep_tempfiles = 0;\t\t// Keep temporary files?\nchar *outname = NULL;\t\t// Output filename, if any\nchar *initname;\t\t\t// File name given to us\n\n\t\t\t\t// List of commands and object files\nchar **phasecmd;\nchar **cppflags;\nchar **preobjs;\nchar **postobjs;\n\n\t\t\t\t// And -D preprocessor words get added here\n#define MAXCPPEXTRA 20\nchar *cppextra[20];\nint cppxindex=0;\n\n\t\t\t\t// Lists of temp and object files\nstruct filelist *Tmphead, *Tmptail;\nstruct filelist *Objhead, *Objtail;\n\n#define MAXCMDARGS 500\nchar *cmdarg[MAXCMDARGS];\t// List of arguments to a command\nint cmdcount = 0;\t\t// Number of command arguments\n\n// Alter the last letter of the initial filename\nchar *alter_suffix(char ch) {\n  char *str = strdup(initname);\n  char *cptr = str + strlen(str) - 1;\n  *cptr = ch;\n  return (str);\n}\n\n// Add a name to the list of temporary files\nvoid addtmpname(char *name) {\n  struct filelist *this;\n  this = (struct filelist *) malloc(sizeof(struct filelist));\n  this->name = name;\n  this->next = NULL;\n  if (Tmphead == NULL) Tmphead = Tmptail = this;\n  else { Tmptail->next = this; Tmptail = this; }\n}\n\n// Remove temporary files and exit\nvoid Exit(int val) {\n  struct filelist *this;\n\n  if (keep_tempfiles == 0)\n    for (this = Tmphead; this != NULL; this = this->next)\n      unlink(this->name);\n  exit(val);\n}\n\n// Add a name to the list of object files\nvoid addobjname(char *name) {\n  struct filelist *this;\n  this = (struct filelist *) malloc(sizeof(struct filelist));\n  this->name = name;\n  this->next = NULL;\n  if (Objhead == NULL) Objhead = Objtail = this;\n  else { Objtail->next = this; Objtail = this; }\n}\n\n// Clear the list of command arguments\nvoid clear_cmdarg(void) {\n  cmdcount = 0;\n}\n\n// Add an argument to the list of command arguments\nvoid add_cmdarg(char *str) {\n  if (cmdcount == MAXCMDARGS) {\n    fprintf(stderr, \"Out of space in cmdargs\\n\");\n    Exit(1);\n  }\n  cmdarg[cmdcount++] = str;\n}\n\n// Return 1 if the string ends in '.'\n// then the given character, 0 otherwise\nint endswith(char *str, char ch) {\n  int len = strlen(str);\n  if (len < 2) return (0);\n  if (str[len - 1] != ch) return (0);\n  if (str[len - 2] != '.') return (0);\n  return (1);\n}\n\n// Given a filename, open it for writing or Exit\nFILE *fopenw(char *filename) {\n  FILE *f = fopen(filename, \"w\");\n  if (f == NULL) {\n    fprintf(stderr, \"Unable to write to file %s\\n\", filename);\n    Exit(1);\n  }\n  return (f);\n}\n\n// Given a filename and a desired suffix,\n// return the name of a temporary file\n// which can be written to, or return NULL\n// if a temporary file cannot be made\nchar *newtempfile(char *origname, char *suffix) {\n  char *name;\n  FILE *handle;\n\n  // First attempt: just add the suffix to the original name\n  name = (char *) malloc(strlen(origname) + strlen(suffix) + 1);\n  if (name != NULL) {\n    strcpy(name, origname);\n    strcat(name, suffix);\n\n    // Now try to open it\n    handle = fopen(name, \"w\");\n    if (handle != NULL) { fclose(handle); addtmpname(name); return (name); }\n  }\n\n  // That filename didn't work. Try one in the TMPDIR\n  name = (char *) malloc(strlen(TMPDIR) + strlen(suffix) + 20);\n  if (name == NULL)\n    return (NULL);\n  sprintf(name, \"%s/%s_XXXXXX\", TMPDIR, suffix);\n\n  // Now try to open it\n  handle = fopenw(name);\n  if (handle != NULL) { fclose(handle); addtmpname(name); return (name); }\n  return (NULL);\n}\n\n// Run the command with arguments in cmdarg[].\n// Replace stdin/stdout by opening in/out as required.\n// If the command doesn't Exit(0), stop.\nvoid run_command(char *in, char *out) {\n  int i, pid, wstatus;\n  FILE *fh;\n\n  if (verbose) {\n    fprintf(stderr, \"Doing: \");\n    for (i = 0; cmdarg[i] != NULL; i++) fprintf(stderr, \"%s \", cmdarg[i]);\n    fprintf(stderr, \"\\n\");\n    if (in != NULL) fprintf(stderr, \"  redirecting stdin from %s\\n\", in);\n    if (out != NULL) fprintf(stderr, \"  redirecting stdout to %s\\n\", out);\n  }\n\n  pid = fork();\n  switch (pid) {\n  case -1:\n    fprintf(stderr, \"fork failed\\n\");\n    Exit(1);\n\n    // Child process\n  case 0:\n    // Close stdin/stdout as required\n    if (in != NULL) {\n      fh = freopen(in, \"r\", stdin);\n      if (fh == NULL) {\n\tfprintf(stderr, \"Unable to freopen %s for reading\\n\", in);\n\tExit(1);\n      }\n    }\n\n    if (out != NULL) {\n      fh = freopen(out, \"w\", stdout);\n      if (fh == NULL) {\n\tfprintf(stderr, \"Unable to freopen %s for writing\\n\", out);\n\tExit(1);\n      }\n    }\n\n    execvp(cmdarg[0], cmdarg);\n    fprintf(stderr, \"exec %s failed\\n\", cmdarg[0]);\n\n    // The parent: wait for child to exit cleanly\n  default:\n    if (waitpid(pid, &wstatus, 0) == -1) {\n      fprintf(stderr, \"waitpid failed\\n\");\n      Exit(1);\n    }\n\n    // Get the child's Exit status and get the parent\n    // to Exit(1) if the Exit status was not zero\n    if (WIFEXITED(wstatus)) {\n      if (WEXITSTATUS(wstatus) != 0) Exit(1);\n    } else {\n      fprintf(stderr, \"child phase didn't exit\\n\"); Exit(1);\n    }\n\n    // The child phase was successful\n    return;\n  }\n}\n\n// Pre-process the file using the C pre-processor\nchar *do_preprocess(char *name) {\n  int i;\n  char *tempname;\n\n  // Build the command\n  clear_cmdarg();\n  add_cmdarg(phasecmd[CPP_PHASE]);\n  for (i = 0; cppflags[i] != NULL; i++)\n    add_cmdarg(cppflags[i]);\n  for (i = 0; i < cppxindex; i++) {\n    add_cmdarg(\"-D\");\n    add_cmdarg(cppextra[i]);\n  }\n  add_cmdarg(name);\n  add_cmdarg(NULL);\n\n  // If this is the last phase, use outname\n  // as the output file, or stdout if NULL.\n  if (last_phase == CPP_PHASE) {\n    run_command(NULL, outname);\n    Exit(0);\n  }\n\n  // Not the last phase, make a temp file\n  tempname = newtempfile(initname, \"_cpp\");\n  run_command(NULL, tempname);\n  return (tempname);\n}\n\n// Assemble the given filename\nchar *do_assemble(char *name) {\n  char *tempname;\n\n  // If this is the last phase, use outname if\n  // not NULL, or change the original file's suffix\n  if (last_phase == ASM_PHASE) {\n    if (outname == NULL)\n      outname = alter_suffix('o');\n    tempname = outname;\n  } else {\n    // Not the last phase, make a temp filename\n    tempname = newtempfile(initname, \"_o\");\n  }\n\n  // Build and run the assembler command\n  clear_cmdarg();\n  add_cmdarg(phasecmd[ASM_PHASE]);\n  add_cmdarg(\"-o\");\n  add_cmdarg(tempname);\n  add_cmdarg(name);\n  add_cmdarg(NULL);\n  run_command(NULL, NULL);\n\n  // Stop now if we are the last phase\n  if (last_phase == ASM_PHASE)\n    Exit(0);\n\n  return (tempname);\n}\n\n// Run several compiler phases to take a\n// pre-processed C file to an assembly file\nchar *do_compile(char *name) {\n  char *tokname, *symname, *astname;\n  char *idxname, *qbename, *asmname;\n\n  // We need to run the scanner, the parser\n  // and the code generator. Get a temp filename\n  // for the scanner's output.\n  tokname = newtempfile(initname, \"_tok\");\n\n  // Build and run the scanner command\n  clear_cmdarg();\n  add_cmdarg(phasecmd[TOK_PHASE]);\n  add_cmdarg(NULL);\n  run_command(name, tokname);\n\n  // Get temp filenames for the parser's output\n  symname = newtempfile(initname, \"_sym\");\n  astname = newtempfile(initname, \"_ast\");\n\n  // Build and run the parser command\n  clear_cmdarg();\n  add_cmdarg(phasecmd[PARSE_PHASE]);\n  add_cmdarg(symname);\n  add_cmdarg(astname);\n  add_cmdarg(NULL);\n  run_command(tokname, NULL);\n\n  // Get some temporary filenames even\n  // if we don't use them.\n  idxname = newtempfile(initname, \"_idx\");\n  qbename = newtempfile(initname, \"_qbe\");\n  asmname = newtempfile(initname, \"_s\");\n\n  // If this phase (compile to assembly) is\n  // the last, use outname if not NULL,\n  // or change the original file's suffix.\n  if (last_phase == GEN_PHASE) {\n    if (outname == NULL)\n      outname = alter_suffix('s');\n    asmname = outname;\n  }\n\n  // Before we run the code generator, see\n  // if the next (QBE or peephole) phase exists.\n  // If not, we go straight to assembly code, so\n  // change the output file's name\n  if (phasecmd[QBEPEEP_PHASE] == NULL) {\n    qbename = asmname;\n  }\n\n  // Build and run the code generator command\n  clear_cmdarg();\n  add_cmdarg(phasecmd[GEN_PHASE]);\n  add_cmdarg(symname);\n  add_cmdarg(astname);\n  add_cmdarg(idxname);\n  add_cmdarg(NULL);\n  run_command(NULL, qbename);\n\n  // Build and run the QBE command or the\n  // peephole optmiser if needed\n  if (phasecmd[QBEPEEP_PHASE] != NULL) {\n    clear_cmdarg();\n    add_cmdarg(phasecmd[QBEPEEP_PHASE]);\n    if (cpu== CPU_QBE) {\n      add_cmdarg(\"-o\");\n      add_cmdarg(asmname);\n      add_cmdarg(qbename);\n    }\n    if (cpu== CPU_6809) {\n      add_cmdarg(\"-o\");\n      add_cmdarg(asmname);\n      add_cmdarg(qbename);\n      add_cmdarg(LIB6809DIR \"/rules.6809\");\n    }\n    add_cmdarg(NULL);\n    run_command(NULL, NULL);\n  }\n\n  // Stop now if we are the last phase\n  if (last_phase == GEN_PHASE)\n    Exit(0);\n\n  return (asmname);\n}\n\n// Link the final executable with all\n// the object files\nvoid do_link(void) {\n  int i;\n  struct filelist *this;\n\n  // Build the command\n  clear_cmdarg();\n  add_cmdarg(phasecmd[LINK_PHASE]);\n  add_cmdarg(\"-o\");\n  add_cmdarg(outname);\n\n  // Insert any files that must come first\n  for (i = 0; preobjs[i] != NULL; i++)\n    add_cmdarg(preobjs[i]);\n\n  // Now add on all the object files and library names\n  for (this = Objhead; this != NULL; this = this->next)\n    add_cmdarg(this->name);\n\n  // Insert any files that must come at the end\n  for (i = 0; postobjs[i] != NULL; i++)\n    add_cmdarg(postobjs[i]);\n  add_cmdarg(NULL);\n  run_command(NULL, NULL);\n}\n\n// Given a CPU/platform name, change the phase\n// programs and object files\nvoid set_phaseprograms(char *cpuname) {\n  if (!strcmp(cpuname, \"qbe\")) {\n    phasecmd = qbephasecmd;\n    cppflags = qbecppflags;\n    preobjs = qbepreobjs;\n    postobjs = qbepostobjs;\n    cpu= CPU_QBE;\n    return;\n  }\n  if (!strcmp(cpuname, \"6809\")) {\n    phasecmd = phasecmd6809;\n    cppflags = cppflags6809;\n    preobjs = preobjs6809;\n    postobjs = postobjs6809;\n    cpu= CPU_6809;\n    return;\n  }\n  fprintf(stderr, \"Unknown CPU/patform: %s\\n\", cpuname);\n  Exit(1);\n}\n\n\n// Print out a usage if started incorrectly\nstatic void usage(char *prog) {\n  fprintf(stderr, \"Usage: %s [-vcESX] [-D ...] [-m CPU] [-o outfile] file [file ...]\\n\",\n\t  prog);\n  fprintf(stderr,\n\t  \"       -v give verbose output of the compilation stages\\n\");\n  fprintf(stderr, \"       -c generate object files but don't link them\\n\");\n  fprintf(stderr, \"       -E pre-process the file, output on stdout\\n\");\n  fprintf(stderr, \"       -S generate assembly files but don't link them\\n\");\n  fprintf(stderr, \"       -X keep temporary files for debugging\\n\");\n  fprintf(stderr, \"       -D ..., set a pre-processor define\\n\");\n  fprintf(stderr, \"       -m CPU, set the CPU e.g. -m 6809, -m qbe\\n\");\n  fprintf(stderr, \"       -o outfile, produce the outfile executable file\\n\");\n  Exit(1);\n}\n\n\n// Main program: check arguments, or print a usage\n// if we don't have any arguments.\n\nint main(int argc, char **argv) {\n  int i, opt;\n\n  phasecmd = qbephasecmd;\n  cppflags = qbecppflags;\n  preobjs = qbepreobjs;\n  postobjs = qbepostobjs;\n\n  // Get the options\n  if (argc < 2)\n    usage(argv[0]);\n  while ((opt = getopt(argc, argv, \"vcESXo:m:D:\")) != -1) {\n    switch (opt) {\n    case 'v': verbose = 1; break;\n    case 'c': last_phase = ASM_PHASE; break;\n    case 'E': last_phase = CPP_PHASE; break;\n    case 'S': last_phase = GEN_PHASE; break;\n    case 'X': keep_tempfiles = 1; break;\n    case 'm': set_phaseprograms(optarg); break;\n    case 'o': outname = optarg; break;\n    case 'D': if (cppxindex >= MAXCPPEXTRA) {\n\t\tfprintf(stderr, \"Too many -D arguments\\n\"); Exit(1);\n\t      }\n\t      cppextra[cppxindex]= optarg; cppxindex++; break;\n    }\n  }\n\n  // Now process the filenames after the arguments\n  if (optind >= argc) usage(argv[0]);\n  for (i = optind; i < argc; i++) {\n    initname = argv[i];\n\n    if (endswith(argv[i], 'c')) {\n      // A C source file, do all major phases\n      addobjname(do_assemble(do_compile(do_preprocess(argv[i]))));\n    } else if (endswith(argv[i], 's')) {\n      // An assembly file, just assemble\n      addobjname(do_assemble(argv[i]));\n    } else if (endswith(argv[i], 'o')) {\n      // Add object files to the list\n      addobjname(argv[i]);\n    } else {\n      fprintf(stderr, \"Input file with unrecognised suffix: %s\\n\", argv[i]);\n      usage(argv[0]);\n    }\n  }\n\n  // Now link all the object files together\n  if (outname == NULL) outname = AOUT;\n  do_link();\n\n  Exit(0);\n  return (0);\n}\n"
  },
  {
    "path": "64_6809_Target/wcc.h",
    "content": "#define AOUT\t\"a.out\"\n#define TMPDIR \t\"/tmp\"\n\n/////////////////\n// QBE SECTION //\n/////////////////\n\n// List of phase command strings\nchar *qbephasecmd[]= {\n  \"cpp\",\t\t\t\t// C pre-processor\n  BINDIR \"/cscan\",\t\t\t// Tokeniser\n  BINDIR \"/cparseqbe\",\t\t\t// Parser\n  BINDIR \"/cgenqbe\",\t\t\t// Code generator\n  \"qbe\",\t\t\t\t// QBE to assembler\n  \"as\",\t\t\t\t\t// Assembler\n  \"cc\"\t\t\t\t\t// Linker\n};\n\n// List of C preprocessor flags\nchar *qbecppflags[]= {\n  \"-nostdinc\",\n  \"-isystem\",\n  INCQBEDIR,\n  NULL\n};\n\n// List of object files that\n// must precede any compiled ones\n// e.g. crt0.o files\nchar *qbepreobjs[]= {\n  NULL\n};\n\n// List of object files and/or\n// libraries that must come\n// after any compiled ones\nchar *qbepostobjs[]= {\n  NULL\n};\n\n//////////////////\n// 6809 SECTION //\n//////////////////\n\n// List of phase command strings\nchar *phasecmd6809[]= {\n  \"cpp\",\t\t\t\t// C pre-processor\n  BINDIR \"/cscan\",\t\t\t// Tokeniser\n  BINDIR \"/cparse6809\",\t\t\t// Parser\n  BINDIR \"/cgen6809\",\t\t\t// Code generator\n  BINDIR \"/cpeep\",\t\t\t// Peephole optmiser\n  \"as6809\",\t\t\t\t// Assembler\n  \"ld6809\"\t\t\t\t// Linker\n};\n\n// List of C preprocessor flags\nchar *cppflags6809[]= {\n  \"-nostdinc\",\n  \"-isystem\",\n  INC6809DIR,\n  NULL\n};\n\n// List of object files that\n// must precede any compiled ones\n// e.g. crt0.o files\nchar *preobjs6809[]= {\n  LIB6809DIR \"/crt0.o\",\n  NULL\n};\n\n// List of object files and/or\n// libraries that must come\n// after any compiled ones\nchar *postobjs6809[]= {\n  LIB6809DIR \"/libc.a\",\n  LIB6809DIR \"/lib6809.a\",\n  NULL\n};\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\n"
  },
  {
    "path": "Readme.md",
    "content": "# A Compiler Writing Journey\n\nIn this Github repository, I'm documenting my journey to write a\nself-compiling compiler for a subset of the C language.\nI'm also writing out the details so that,\nif you want to follow along, there will be an explanation of what\nI did, why, and with some references back to the theory of compilers.\n\nBut not too much theory, I want this to be a practical journey.\n\nHere are the steps I've taken so far:\n\n + [Part  0](00_Introduction/Readme.md):  Introduction to the Journey\n + [Part  1](01_Scanner/Readme.md):       Introduction to Lexical Scanning\n + [Part  2](02_Parser/Readme.md):        Introduction to Parsing\n + [Part  3](03_Precedence/Readme.md):    Operator Precedence\n + [Part  4](04_Assembly/Readme.md):      An Actual Compiler\n + [Part  5](05_Statements/Readme.md):    Statements\n + [Part  6](06_Variables/Readme.md):     Variables\n + [Part  7](07_Comparisons/Readme.md):   Comparison Operators\n + [Part  8](08_If_Statements/Readme.md): If Statements\n + [Part  9](09_While_Loops/Readme.md):   While Loops\n + [Part 10](10_For_Loops/Readme.md):     For Loops\n + [Part 11](11_Functions_pt1/Readme.md): Functions, part 1\n + [Part 12](12_Types_pt1/Readme.md):     Types, part 1\n + [Part 13](13_Functions_pt2/Readme.md): Functions, part 2\n + [Part 14](14_ARM_Platform/Readme.md):  Generating ARM Assembly Code\n + [Part 15](15_Pointers_pt1/Readme.md):  Pointers, part 1\n + [Part 16](16_Global_Vars/Readme.md):   Declaring Global Variables Properly\n + [Part 17](17_Scaling_Offsets/Readme.md): Better Type Checking and Pointer Offsets\n + [Part 18](18_Lvalues_Revisited/Readme.md): Lvalues and Rvalues Revisited\n + [Part 19](19_Arrays_pt1/Readme.md):    Arrays, part 1\n + [Part 20](20_Char_Str_Literals/Readme.md): Character and String Literals\n + [Part 21](21_More_Operators/Readme.md): More Operators\n + [Part 22](22_Design_Locals/Readme.md): Design Ideas for Local Variables and Function Calls\n + [Part 23](23_Local_Variables/Readme.md): Local Variables\n + [Part 24](24_Function_Params/Readme.md): Function Parameters\n + [Part 25](25_Function_Arguments/Readme.md): Function Calls and Arguments\n + [Part 26](26_Prototypes/Readme.md):    Function Prototypes\n + [Part 27](27_Testing_Errors/Readme.md): Regression Testing and a Nice Surprise\n + [Part 28](28_Runtime_Flags/Readme.md): Adding More Run-time Flags\n + [Part 29](29_Refactoring/Readme.md):   A Bit of Refactoring\n + [Part 30](30_Design_Composites/Readme.md): Designing Structs, Unions and Enums\n + [Part 31](31_Struct_Declarations/Readme.md): Implementing Structs, Part 1\n + [Part 32](32_Struct_Access_pt1/Readme.md): Accessing Members in a Struct\n + [Part 33](33_Unions/Readme.md):        Implementing Unions and Member Access\n + [Part 34](34_Enums_and_Typedefs/Readme.md): Enums and Typedefs\n + [Part 35](35_Preprocessor/Readme.md):  The C Pre-Processor\n + [Part 36](36_Break_Continue/Readme.md): `break` and `continue`\n + [Part 37](37_Switch/Readme.md):        Switch Statements\n + [Part 38](38_Dangling_Else/Readme.md): Dangling Else and More\n + [Part 39](39_Var_Initialisation_pt1/Readme.md): Variable Initialisation, part 1\n + [Part 40](40_Var_Initialisation_pt2/Readme.md): Global Variable Initialisation\n + [Part 41](41_Local_Var_Init/Readme.md): Local Variable Initialisation\n + [Part 42](42_Casting/Readme.md):       Type Casting and NULL\n + [Part 43](43_More_Operators/Readme.md): Bugfixes and More Operators\n + [Part 44](44_Fold_Optimisation/Readme.md): Constant Folding\n + [Part 45](45_Globals_Again/Readme.md): Global Variable Declarations, revisited\n + [Part 46](46_Void_Functions/Readme.md): Void Function Parameters and Scanning Changes\n + [Part 47](47_Sizeof/Readme.md):        A Subset of `sizeof`\n + [Part 48](48_Static/Readme.md):        A Subset of `static`\n + [Part 49](49_Ternary/Readme.md):       The Ternary Operator\n + [Part 50](50_Mop_up_pt1/Readme.md):    Mopping Up, part 1\n + [Part 51](51_Arrays_pt2/Readme.md):    Arrays, part 2\n + [Part 52](52_Pointers_pt2/Readme.md):  Pointers, part 2\n + [Part 53](53_Mop_up_pt2/Readme.md):    Mopping Up, part 2\n + [Part 54](54_Reg_Spills/Readme.md):    Spilling Registers\n + [Part 55](55_Lazy_Evaluation/Readme.md): Lazy Evaluation\n + [Part 56](56_Local_Arrays/Readme.md):  Local Arrays\n + [Part 57](57_Mop_up_pt3/Readme.md):    Mopping Up, part 3\n + [Part 58](58_Ptr_Increments/Readme.md): Fixing Pointer Increments/Decrements\n + [Part 59](59_WDIW_pt1/Readme.md):      Why Doesn't It Work, part 1\n + [Part 60](60_TripleTest/Readme.md):    Passing the Triple Test\n + [Part 61](61_What_Next/Readme.md):     What's Next?\n + [Part 62](62_Cleanup/Readme.md):       Code Cleanup\n + [Part 63](63_QBE/Readme.md):           A New Backend using QBE\n + [Part 64](64_6809_Target/Readme.md):   A Backend for the 6809 CPU\n\nI've stopped work on *acwj* and now I'm writing a new language\ncalled [alic](https://github.com/DoctorWkt/alic) from scratch. Check it out!\n\n## Copyrights\n\nI have borrowed some of the code, and lots of ideas, from the \n[SubC](http://www.t3x.org/subc/) compiler written by Nils M Holm.\nHis code is in the public domain. I think that my code is substantially\ndifferent enough that I can apply a different license to my code.\n\nUnless otherwise noted,\n\n + all source code and scripts are (c) Warren Toomey under\n   the GPL3 license.\n + all non-source code documents (e.g. English documents,\n   image files) are (c) Warren Toomey under the Creative\n   Commons BY-NC-SA 4.0 license.\n"
  }
]